02A pairs experiments
Experiment related scripts
Read pairwise competition outcomes that are determined by colony counts on plates.
Filter out ambiguous pairs and later fill in the data hole by CASEU results.
Map pairs and isolates to the 96-well plate layout
Read the pairwise competitive outcomes determined by colony counting on TSA
Generate table for manual key-in
Then I manually checked the scanned plate images of competitive pairs. The plate images are saved in folder plate_scan/high_order_plate_scan/ and divided according the experimental batches.
| B2 |
2.6, 2.8, 7.1, 8.4, 10.2, 11.1 |
| C |
11.1 isolate 1 |
| C2 |
11.2 |
| D |
1.2, 1.4, 1.6, 1.7, 4.1, 11.5 |
There are 186x3=558 outcomes of pairwise competitions.
Rows: 558 Columns: 11
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Experiment, Community
dbl (8): Isolate1, Isolate2, Isolate1Freq, Isolate2Freq, ColonyCount, ColonyCount1, ColonyCount2, D...
lgl (1): Contamination
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
67 pairs without determined outcomes of pairwise competitions will be determined by using CASEU method
186 pair IDs saved in pairs_ID
Rows: 186 Columns: 3
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (2): Isolate1, Isolate2
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Ambiguous pairs and isolates on TSA agar plates
There are 67 pair-freqs that I don’t know the competitive outcomes by TSA plate counting. The ambiguous pairs will be later examined by using selective media or Sanger sequencing.
Rows: 67 Columns: 7
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Experiment, Community
dbl (4): Isolate1, Isolate2, Isolate1Freq, Isolate2Freq
lgl (1): Contamination
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
28 pairs
`summarise()` has grouped output by 'Community', 'Isolate1'. You can override using the `.groups` argument.
36 isolates involved in the ambiguous pairs.
Rows: 36 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Community, ExpID
dbl (2): Isolate, ID
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Map pairs and isolates to the DW96 plate layout
Rows: 13 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (3): CommunitySize, CommunityPairSize, CommunitiyMotifSize
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Each plate has 96 rows and has the following variables
Rows: 1248 Columns: 10
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (7): Experiment, PlateLayout, Well, Community, Isolate1, Isolate2, Plate
dbl (2): Isolate1Freq, Isolate2Freq
lgl (1): MixIsolate
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
spec_tbl_df [1,248 × 10] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
$ Experiment : chr [1:1248] "Transitivity_B2" "Transitivity_B2" "Transitivity_B2" "Transitivity_B2" ...
$ PlateLayout : chr [1:1248] "933" "933" "933" "933" ...
$ Well : chr [1:1248] "A01" "A02" "A03" "A04" ...
$ MixIsolate : logi [1:1248] TRUE TRUE TRUE TRUE TRUE TRUE ...
$ Community : chr [1:1248] "C11R1" "C11R1" "C11R1" "C11R1" ...
$ Isolate1 : chr [1:1248] "1" "1" "1" "1" ...
$ Isolate2 : chr [1:1248] "1" "2" "3" "4" ...
$ Plate : chr [1:1248] "P1" "P1" "P1" "P1" ...
$ Isolate1Freq: num [1:1248] 50 50 50 50 50 50 50 50 50 50 ...
$ Isolate2Freq: num [1:1248] 50 50 50 50 50 50 50 50 50 50 ...
- attr(*, "spec")=
.. cols(
.. Experiment = col_character(),
.. PlateLayout = col_character(),
.. Well = col_character(),
.. MixIsolate = col_logical(),
.. Community = col_character(),
.. Isolate1 = col_character(),
.. Isolate2 = col_character(),
.. Plate = col_character(),
.. Isolate1Freq = col_double(),
.. Isolate2Freq = col_double()
.. )
- attr(*, "problems")=<externalptr>
Read plate layout by batch
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.
Plate layout that takes different initial frequencies:
The only exception is plate C11R1 in batch C, which only has one plate.
02B CASEU sanger sequencing
To determine the relative abundance of of ambiguous pairs in competitive assays.
Use CASEU packages to analyse the Sanger sequencing of mixture culture.
Sanger sequencing protocol preparation. Experimental protocol files are saved in folder output/protocol/
[1] "caseu_calibration.Rmd" "caseu_genewiz.pdf" "caseu_genewiz.Rmd" "caseu_pcr.pdf"
[5] "caseu_pcr.Rmd" "caseu_protocol.pdf" "caseu_protocol.Rmd"
Once we got the mixture Sanger sequences back, we implement analysis by using CASEU (Compositional analysis by Sanger electropherogram unmixing), an R package designed for quantifying relative abundance of Sanger sequences mixture. source code. Install CASEU from bitbucket.
Check out package vignette.
devtools::install_bitbucket('dattamanoshi/caseu') # Install CASEU package
library(CASEU)
Test on example data
Test the example code and data.
Fit Sanger sequences of a mixed culture of four strains. This step may take a few seconds.
library(CASEU)
data('fourStrainExpt') # load an example dataset
results <-
fitSangerMixture(mixture=fourStrainExpt$mixture, # mixture
components = fourStrainExpt$components, # Four individual 16S sequences
verbose=TRUE)
save(results, file = here::here("data/temp/CASEU_test_results1.Rdata"))
Fitted mixture sanger electropherogram output
CASEU pilot1
The plate layout of PCR plate and list of samples are specified in output/protocol/protocol_20190813_Sanger_seq_prep.pdf.
The isolates used in this round is from the list below.
isolates
| C11R1 isolate 1 |
A |
Pseudomonas |
| C1R7 isolate 2 |
B |
Pseudomonas |
| C1R7 isolate 1 |
C |
Enterobacter |
| C1R7 isolate 7 |
D |
Raoultella |
Read trace matrices for isolates and mixtures
Rows: 16 Columns: 8
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): MixtureName, Treatment, Isolate1, Isolate2
dbl (4): Isolate1Freq, Isolate2Freq, Isolate1FreqPredicted, Isolate2FreqPredicted
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Plot the expected isolate frequency vs. CASEU predicted frequency
Rows: 16 Columns: 8
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): MixtureName, Treatment, Isolate1, Isolate2
dbl (4): Isolate1Freq, Isolate2Freq, Isolate1FreqPredicted, Isolate2FreqPredicted
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Saving 7.5 x 7.5 in image
CASEU pilot2
The plate layout of PCR plate and list of samples are specified in output/protocol/protocol_20190813_Sanger_seq_prep.pdf. There are 32 samples from pairwise competition and 16 samples from control. Also read Sylvie’s data.
Isolates A B C D in control are the isolates below.
| C11R1 isolate 1 |
A |
Pseudomonas |
| C1R7 isolate 2 |
B |
Pseudomonas |
| C1R7 isolate 1 |
C |
Enterobacter |
| C1R7 isolate 7 |
D |
Raoultella |
Control pairs
In the 12 control synthetic pairs that were made of 4 isolates, compare these pairs’ OD frequencies, colony counts, and CASEU predictions.
Read CASEU predicted frequencies and colony count frequencies in the 12 control pairs.
Rows: 36 Columns: 9
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): MixtureName, User, Treatment, Isolate1, Isolate2
dbl (4): Isolate1Freq, Isolate2Freq, Isolate1FreqPredicted, Isolate2FreqPredicted
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 12 Columns: 10
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): MixtureName, User, Treatment, Isolate1, Isolate2
dbl (5): Isolate1Freq, Isolate2Freq, Isolate1Colony, Isolate2Colony, Dilution
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Join the CASEU predicted result of control pairs in CASEU_pilot2 with the plating result in CASEU_pilot2_plating. The pair CYC_control_50_50_CD has a lot colonies and the colony count of C is just approximation (n=300)
Plot the CASEU predictio vs. colony counts and CASEU prediction vs. OD frequencies
CASEU pilot3
The plate layout of PCR plate and list of samples are specified in output/protocol/protocol_20190923_SequalPrep_Sanger_prep.pdf.
Read trace matrices for isolates and mixtures
Rows: 42 Columns: 9
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): MixtureName, Community
dbl (7): Isolate1Freq, Isolate2Freq, Isolate1, Isolate2, Isolate1FreqPredicted, Isolate2FreqPredict...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

CASEU pilot4
The plate layout of PCR plate and list of samples are specified in output/protocol/protocol_20191007_Sanger_seq_prep.pdf.
Read trace matrices for isolates and mixtures
Rows: 30 Columns: 9
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): MixtureName, Community
dbl (7): Isolate1Freq, Isolate2Freq, Isolate1, Isolate2, Isolate1FreqPredicted, Isolate2FreqPredict...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

02C pairs_OD_CFU
Error propagation theory
Derive isolates’ \(\epsilon\) from T8 data and calculate uncertatinty using error propagation theory
Convert T0 OD frequency \(f^O\) to CFU frequency \(f^C\) and estimate the uncertainty in converted CFU frequencies at T8. Output data/temp/pairs_CFU_freq_uncertainty.csv
Uncertainty in epsilon
The uncertainties in each isolate’ epsilon \(\epsilon_A = \frac{OD_A DF_A v_A}{CFU_A}\) comes from four parts:
- \(DF\): Dilution factors. The uncertainty comes from the pipetting in serial dilution, which is calcaulted below.
- \(v\): Plating volumes. The systematic error for P20 set at 20 uL is 0.4 uL.
- \(CFU\): CFU counts. The uncertainty in CFU follows poisson distribution, which means that the variance is the same as the mean (measured CFU). The standard deviation is \(\sqrt{CFU}\).
- \(OD\): OD measurement. The uncertainty in measuring OD in plate reader, which is assumed to be 0.001.
Dilution factor
The uncertainty in dilution factor comes from the pipetting steps in serial dilution, which include two pipetting volumes:
V1: serial dispensing 10 uL of diluted solution using mP20. It has uncertainty ErrorV1 2 uL.
V2: dispense 90 uL of PBS using mP200. It has uncertainty ErrorV2 0.4 uL.
For dilution factor \(10^{n}\), it has the the mean \((\frac{V_1}{V_1+V_2})^n\). To obtain the uncertainty in the measured mean, first we caluculate the partial derivatives \(\frac{\partial DF}{\partial V_1}\) and \(\frac{\partial DF}{\partial V_2}\). Then the uncertainty \(\delta DF = \sqrt{(\frac{\partial DF}{\partial V_1}\delta V_1)^2 + (\frac{\partial DF}{\partial V_2}\delta V_2)^2}\)
By using error propagation theroy, the uncertainty in isolates epsilon has the form
\[\delta \epsilon = \sqrt{(\frac{\partial \epsilon}{\partial DF}\delta DF)^2 +(\frac{\partial \epsilon}{\partial CFU}\delta CFU)^2 + (\frac{\partial \epsilon}{\partial OD}\delta OD)^2 + (\frac{\partial \epsilon}{\partial V}\delta V)^2}\]
Rows: 68 Columns: 19
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (18): Isolate, OD620, ColonyCount, DilutionFactor, CFU, OD, V, ErrorCFU, ErrorOD, ErrorV, DF, E...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
There are 7 isolates that have either 0 CFU or negative OD value, so they don’t have epsilon values.
Convert T0 OD frequencies to CFU frequencies
The outcome of pairwise competition were determined by comparing the frequency changes between T0 and T8. The T8 frequencies were determined by plating the mature media on rich agar media on which the colonies were counted, whereas T0 frequencies were set to 95/5, 50/50 and 5/95 by mixing two isolate inocula with equal OD. In this section, I will use the OD-CFU conversion coefficient \(\epsilon\) derived from T8 isolate data to convert T0 OD frequencies into CFU frequencies. In specific, the CFU frequency of isolate 1 \(f^C_1\) of a pair can be derived from OD frequencies of isolate 1 and 2 \(f^O_1 ,f^O_2\), which have the relationship below.
\(f^C_1 = \frac{f^o_1\epsilon_1DFv}{f^o_1\epsilon_1DFv + f^o_2\epsilon_2DFv}=\frac{f^o_1\epsilon_1}{f^o_1\epsilon_1 + f^o_2\epsilon_2}\)
where \(\epsilon\) of each isolate was pre-calculated from T8 dataset. DF and v are the same in conversion.
Rows: 1116 Columns: 7
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Community, Time
dbl (5): Isolate1, Isolate2, Isolate1Freq, Isolate2Freq, Isolate1CFUFreq
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Uncertainty in T0 CFU frequencies
Write CFU frequencies to data/temp/pairs_CFU_freq_uncertainty.csv
Rows: 1116 Columns: 10
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Community, Time, RawDataType
dbl (6): Isolate1, Isolate2, Isolate1Freq, Isolate2Freq, Isolate1CFUFreq, ErrorIsolate1CFUFreq
lgl (1): Contamination
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
02D determine pairwise interaction
Combine outcomes of pairwise competition from CFU counts and CASEU
Raw data (e.g., CFU counts and CASEU Sanger sequences) are processed and generated into temporary result csv:
02B-CASEU_sanger_seq reads CASEU raw data and outputs temp/CASEU_pilot2.csv and temp/CASEU_pilot3.csv. Both files are CASEU predicted T8 frequencies.
02C-pairs_OD_CFU reads pair_competition and dilution factor data, and it outputs temp/pairs_CFU_freq_uncertainty.csv, which has the T0 OD-converted CFU frequencies and T8 CFU frequencies with uncertainties.
Note that if a pair has both CFU and CASEU result, CASEU will overwrite the CFU result
The script in this section returns a data.frame pairs_freq that has the following variables:
Community
Isolate1 and Isolate2: indices of isolates within a community. The number of isolate1 is always smaller than isolate2
Isolate1InitialODFreq and Isolate2InitialODFreq: 5, 50 or 95. The initial OD frequencies of isolates at T0. This two serve as discrete grouping variables.
Time: T0 or T8.
Isolate1MeasuredFreq: the measured frequency od isolate1 in the pair.
ErrorIsolate1MeasuredFreq: the uncertainty of Isolate1MeasuredFreq.
RawDataType: OD, ODtoCFU, CFU, Sanger (CASEU). The raw data type in which the isolate frequencies were measured.
Contamination: logical. There are contaminations in three pairs at T8 plates.
186x3x2=1116 pair-freq at two time points
Rows: 1116 Columns: 10
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Community, Time, RawDataType
dbl (6): Isolate1, Isolate2, Isolate1InitialODFreq, Isolate2InitialODFreq, Isolate1MeasuredFreq, Er...
lgl (1): Contamination
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
There is one pair-freq that cannot be specified because of contamination.
Determine pairwise interactions
Plot frequency changes. Output figure of CFU frequency changes to output/figure/pairs_freq_change_uncertainty.pdf
Table of all 27 possible combinations of fitness function and their interaction types
Rows: 27 Columns: 6
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): InteractionType, InteractionTypeFiner, FreqFunc
dbl (3): FromRare, FromMedium, FromAbundant
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Table of interaction types
Rows: 186 Columns: 13
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): Community, FreqFunc, PairIsolate1MeasuredFreqT8, InteractionType, InteractionTypeFiner
dbl (7): Isolate1, Isolate2, FromRare, FromMedium, FromAbundant, From, To
lgl (1): Isolate1Win
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Interaction table
Rows: 32 Columns: 5
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): FromRare, FromMedium, FromAbundant, InteractionType
dbl (1): Count
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Isolate tournament
Tournament ranks of each isolate. Note that I consider neturality and bistability as draw in the tournament.
Score: the competitive scores of isolate. This score is computed by the formula: number of wins - number of loses + 0 * number of draws.
Game: number of pairwise competition the isolate has played. The number of games an isolate plated within a community should be community size minus one.
Rank: the ranks based on Score. The ranks range from 1 to the focal community size. Isolates with the same scores in a community are given the same rank.
PlotRank: continuous rank for plotting convenience.
02E competition phylogeny
Isolates’ RDP taxonomy
Rows: 186 Columns: 11
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (7): Community, Family1, Family2, Genus1, Genus2, PairFermenter, PairFamily
dbl (2): Isolate1, Isolate2
lgl (2): Fermenter1, Fermenter2
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Isolates’ 16S sequence difference
Rows: 186 Columns: 5
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (4): Isolate1, Isolate2, SeqDifference, SeqLength
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Isolates’ branch distances on phylogenetic tree (deprecated)
Rows: 186 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (2): Isolate1, Isolate2
lgl (1): PairTreeDistance
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Summary
Read and combine pairs data
186 pairs
Rows: 186 Columns: 17
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (9): Community, InteractionType, InteractionTypeFiner, Family1, Family2, Genus1, Genus2, PairFe...
dbl (6): Isolate1, Isolate2, From, To, SeqDifference, SeqLength
lgl (2): Fermenter1, Fermenter2
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Pairs data.frame melted by T0/T8 and three initial frequencies. 186x3x2=1116
Rows: 1116 Columns: 20
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (9): Community, Time, RawDataType, Family1, Family2, Genus1, Genus2, PairFermenter, PairFamily
dbl (8): Isolate1, Isolate2, Isolate1InitialODFreq, Isolate2InitialODFreq, Isolate1MeasuredFreq, Er...
lgl (3): Contamination, Fermenter1, Fermenter2
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Plot outcomes types
Four example outcomes: bistability, coexistence, exclusion, and neutrality
Rows: 3 Columns: 7
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Community, InteractionType, InteractionTypeFiner
dbl (4): Isolate1, Isolate2, From, To
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Warning: `guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.

Four example outcomes: bistability, coexistence, exclusion, and neutrality
Rows: 5 Columns: 7
── Column specification ───────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Community, InteractionType, InteractionTypeFiner
dbl (4): Isolate1, Isolate2, From, To
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
`summarise()` has grouped output by 'InteractionTypeFiner'. You can override using the `.groups` argument.

Pairs taxonomy vs. outcome of pairwise competition
`summarise()` has grouped output by 'PairFermenter'. You can override using the `.groups` argument.
`summarise()` has grouped output by 'PairFamily'. You can override using the `.groups` argument.
`summarise()` has grouped output by 'SeqDifference'. You can override using the `.groups` argument.
RDP taxonomy
Fermenter vs. Interaction type

Family vs. Interaction type

Pairwise 16S differences
Pairwise 16S differences

Coarsed-grained 16S sequence difference


Relative abundance within pairs
Relative abundance of fermenter vs. non-fermenter pairs
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 1 rows containing non-finite values (stat_bin).

Relative abundance of Enterobacteriaceae and Pseudomonadaceae pairs
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 1 rows containing non-finite values (stat_bin).

LS0tCnRpdGxlOiAiQW5hbHlzaXMgb24gcGFpcndpc2UgY29tcGV0aXRpb24gYXNzYXlzIgphdXRob3I6ICJDaGFuZy1ZdSBDaGFuZyIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGfQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGUgPSBGQUxTRSwgZWNobyA9IEZBTFNFKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGNvd3Bsb3QpCnJ1bl9zY3JpcHRzIDwtIEYKY29tbXVuaXRpZXMgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvY29tbXVuaXRpZXMuY3N2IikpCmBgYAoKCiMgR29hbAoKLSBDb21iaW5lIGFuZCByZWFkIGRhdGEgY3N2IGZyb20gMDJBIHRvIDAyRAoKLSBNYXRjaCBhbmQgY29tcGFyZSBpc29sYXRlcycgaW5mb3JtYXRpb24gdG8gb3V0Y29tZSBvZiBwYWlyd2lzZSBjb21wZXRpdGlvbgogICAgLSBSRFAgdGF4b25vbXkgKGUuZy4sIGZhbWlseSBhbmQgZ2VudXMpCiAgICAtIDE2UyBkaWZmZXJlbmNlcwogICAgLSBEaXN0YW5jZSBvbiBwaHlsb2dlbmV0aWMgdHJlZQogICAgLSBNb25vY3VsdHVyZSBncm93dGggcmF0ZSAKCi0gVGhlIFIgc2NyaXB0cyAoc291cmNlZCBpbiB0aGlzIFJtZCkgY2FuIGJlIHJ1biBleHRlcm5hbGx5IHRvIFJzdHVkaW8uCi0gVGhlIFIgc2NyaXB0cyBhcmUgb25seSBmb3Igc2F2aW5nIFIgZnVuY3Rpb25zLCBwcm9jZXNzaW5nIHJhdyBhbmQgdGVtcG9yYXJ5IGRhdGEuCi0gQWxsIHZpc3VhbGl6YXRpb24gY29kZXMgYXJlIGluIHRoaXMgUm1kIGZpbGUuCgojIDAyQSBwYWlycyBleHBlcmltZW50cwoKLSBFeHBlcmltZW50IHJlbGF0ZWQgc2NyaXB0cwoKLSBSZWFkIHBhaXJ3aXNlIGNvbXBldGl0aW9uIG91dGNvbWVzIHRoYXQgYXJlIGRldGVybWluZWQgYnkgY29sb255IGNvdW50cyBvbiBwbGF0ZXMuIAoKLSBGaWx0ZXIgb3V0IGFtYmlndW91cyBwYWlycyBhbmQgbGF0ZXIgZmlsbCBpbiB0aGUgZGF0YSBob2xlIGJ5IENBU0VVIHJlc3VsdHMuIAoKLSBNYXAgcGFpcnMgYW5kIGlzb2xhdGVzIHRvIHRoZSA5Ni13ZWxsIHBsYXRlIGxheW91dAoKCiMjIFJlYWQgdGhlIHBhaXJ3aXNlIGNvbXBldGl0aXZlIG91dGNvbWVzIGRldGVybWluZWQgYnkgY29sb255IGNvdW50aW5nIG9uIFRTQQoKR2VuZXJhdGUgdGFibGUgZm9yIG1hbnVhbCBrZXktaW4KCmBgYHtyIGV2YWwgPSBGfQppZiAoRkFMU0UpIHNvdXJjZSgic2NyaXB0LzAyQS1wYWlyc19leHBlcmltZW50LTAxLXBhaXJ3aXNlX21hbnVhbF9rZXlfaW4uUiIpCmBgYAoKVGhlbiBJIG1hbnVhbGx5IGNoZWNrZWQgdGhlIHNjYW5uZWQgcGxhdGUgaW1hZ2VzIG9mIGNvbXBldGl0aXZlIHBhaXJzLiBUaGUgcGxhdGUgaW1hZ2VzIGFyZSBzYXZlZCBpbiBmb2xkZXIgYHBsYXRlX3NjYW4vaGlnaF9vcmRlcl9wbGF0ZV9zY2FuL2AgYW5kIGRpdmlkZWQgYWNjb3JkaW5nIHRoZSBleHBlcmltZW50YWwgYmF0Y2hlcy4KCkJhdGNoIHwgQ29tbXVuaXR5Ci0tLS0tLXwtLS0tLS0tLS0tLQpCMiAgICB8IDIuNiwgMi44LCA3LjEsIDguNCwgMTAuMiwgMTEuMQpDICAgICB8IDExLjEgaXNvbGF0ZSAxCkMyICAgIHwgMTEuMgpEICAgICB8IDEuMiwgMS40LCAxLjYsIDEuNywgNC4xLCAxMS41CgoKYGBge3Igd2FybmluZyA9IEZ9CiMgUmVhZCByZXN1bHQgY29sb255IGNvdW50cyBhbmQgZGlsdXRpb24gZmFjdG9yCmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJBLXBhaXJzX2V4cGVyaW1lbnQtMDItY29sb255X2NvdW50LlIiKQpgYGAKClRoZXJlIGFyZSAxODZ4Mz01NTggb3V0Y29tZXMgb2YgcGFpcndpc2UgY29tcGV0aXRpb25zLgoKYGBge3J9CnBhaXJzX2NvbXBldGl0aW9uIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wYWlyc19jb21wZXRpdGlvbi5jc3YiKSkKcGFpcnNfY29tcGV0aXRpb24KYGBgCgo2NyBwYWlycyB3aXRob3V0IGRldGVybWluZWQgb3V0Y29tZXMgb2YgcGFpcndpc2UgY29tcGV0aXRpb25zIHdpbGwgYmUgZGV0ZXJtaW5lZCBieSB1c2luZyBDQVNFVSBtZXRob2QKCmBgYHtyfQpwYWlyc19jb21wZXRpdGlvbiAlPiUKICBmaWx0ZXIoaXMubmEoQ29sb255Q291bnQpKQpgYGAKCjE4NiBwYWlyIElEcyBzYXZlZCBpbiBgcGFpcnNfSURgCgpgYGB7cn0KcGFpcnNfSUQgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL3BhaXJzX0lELmNzdiIpKQpwYWlyc19JRApgYGAKCgoKIyMgQW1iaWd1b3VzIHBhaXJzIGFuZCBpc29sYXRlcyBvbiBUU0EgYWdhciBwbGF0ZXMKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQS1wYWlyc19leHBlcmltZW50LTAzLXBhaXJ3aXNlX2FtYmlndW91cy5SIikKYGBgCgpUaGVyZSBhcmUgNjcgcGFpci1mcmVxcyB0aGF0IEkgZG9uJ3Qga25vdyB0aGUgY29tcGV0aXRpdmUgb3V0Y29tZXMgYnkgVFNBIHBsYXRlIGNvdW50aW5nLiBUaGUgYW1iaWd1b3VzIHBhaXJzIHdpbGwgYmUgbGF0ZXIgZXhhbWluZWQgYnkgdXNpbmcgc2VsZWN0aXZlIG1lZGlhIG9yIFNhbmdlciBzZXF1ZW5jaW5nLiAKCmBgYHtyfQpwYWlyc19hbWJpZ3VvdXMgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL3BhaXJzX2FtYmlndW91cy5jc3YiKSkKcGFpcnNfYW1iaWd1b3VzCmBgYAoKMjggcGFpcnMKCmBgYHtyfQpwYWlyc19hbWJpZ3VvdXMgJT4lIAogIGdyb3VwX2J5KENvbW11bml0eSwgSXNvbGF0ZTEsIElzb2xhdGUyKSAlPiUKICBzdW1tYXJpemUoQ291bnQgPSBuKCkpCmBgYAoKMzYgaXNvbGF0ZXMgaW52b2x2ZWQgaW4gdGhlIGFtYmlndW91cyBwYWlycy4gCgpgYGB7cn0KaXNvbGF0ZXNfYW1iaWd1b3VzIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9pc29sYXRlc19hbWJpZ3VvdXMuY3N2IikpCmlzb2xhdGVzX2FtYmlndW91cwpgYGAKCgoKIyMgTWFwIHBhaXJzIGFuZCBpc29sYXRlcyB0byB0aGUgRFc5NiBwbGF0ZSBsYXlvdXQKCmBgYHtyIHdhcm5pbmcgPSBGfQpwbGF0ZXNfbmFtZSA8LSBjKCJwbGF0ZV9CMl85MzMiLCAicGxhdGVfQjJfNDQ0IiwgInBsYXRlX0NfQzExUjEiLCAicGxhdGVfQzJfMTNBIiwgInBsYXRlX0MyXzEzQiIsICJwbGF0ZV9EXzc1IiwgInBsYXRlX0RfNTU0MyIpCnNvdXJjZSgic2NyaXB0LzAyQS1wYWlyc19leHBlcmltZW50LTA0LXBhaXJ3aXNlX3BsYXRlX2xheW91dC5SIikKYGBgCgpFYWNoIHBsYXRlIGhhcyA5NiByb3dzIGFuZCBoYXMgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXMKCmBgYHtyfQpwbGF0ZXMgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvcGxhdGVzLmNzdiIpKQpzdHIocGxhdGVzKQpgYGAKClJlYWQgcGxhdGUgbGF5b3V0IGJ5IGJhdGNoCgpgYGB7cn0KZHJhd19wbGF0ZV9mcm9tX2RmIDwtIGZ1bmN0aW9uKAogIGRmLAogIHdlbGxfc2l6ZSA9IDUsCiAgdGV4dF9zaXplID0gMywKICBhbm5vdGF0aW9uID0gVFJVRSwKICBhbm5vdGF0ZV9lYWNoX3dlbGwgPSBUUlVFLAogIGZpbGxfbGVnZW5kID0gRiwKICB2anVzdCA9IDAsCiAgLi4uCikgewogICMgQ2hlY2sKICBzdG9waWZub3QoCiAgICBpcy5kYXRhLmZyYW1lKGRmKSwKICAgICJXZWxsIiAlaW4lIG5hbWVzKGRmKSwKICAgICJUZXh0TGFiZWwiICVpbiUgbmFtZXMoZGYpIHwgIkZpbGxMYWJlbCIgJWluJSBuYW1lcyhkZikKICApCgogICMgTWFrZSBwbGF0ZQogIHBsYXRlIDwtIGRmICU+JQogICAgbXV0YXRlKAogICAgICBSb3cgPSBtYXRjaChzdWJzdHIoV2VsbCwgMSwgMSksIExFVFRFUlNbMTo4XSksCiAgICAgIENvbCA9IHN1YnN0cihXZWxsLCAyLCAzKSAlPiUgYXMubnVtZXJpYygpLAogICAgKSAlPiUKICAgIGZpbHRlcighZ3JlcGwoImJsYW5rIiwgLiRGaWxsTGFiZWwpKSAlPiUKICAgIG11dGF0ZShGaWxsTGFiZWwgPSBhcy5jaGFyYWN0ZXIoRmlsbExhYmVsKSkKCiAgIyBFbXB0eSB3ZWxsCiAgZW1wdHlfd2VsbCA8LSBkYXRhLmZyYW1lKAogICAgUm93ID0gcmVwKDE6OCwgZWFjaCA9IDEyKSwKICAgIENvbCA9IHJlcCgxOjEyLCA4KQogICkKCiAgIyBQbG90IGJsYW5rIHBsYXRlCiAgaWYgKGFsbChpcy5uYShwbGF0ZSRGaWxsTGFiZWwpKSkgewogICAgcmV0dXJuKAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gZW1wdHlfd2VsbCwgYWVzKHggPSBDb2wsIHkgPSBSb3cpLCBzaGFwZSA9IDEsIHNpemUgPSB3ZWxsX3NpemUsIGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BKSArCiAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAiIiwgYnJlYWtzID0gMToxMiwgbGFiZWxzID0gMToxMiwgbGltaXRzID0gYygxLCAxMiksIHBvc2l0aW9uID0gInRvcCIpICsKICAgICAgICBzY2FsZV95X3JldmVyc2UobmFtZSA9ICIiLCBsaW0gPSBjKDgsIDEpLCBicmVha3MgPSAxOjgsIGxhYmVscyA9IExFVFRFUlNbMTo4XSkgKwogICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgIE5VTEwKICAgICkKICB9CgogICMgUGxvdCBzZWdtZW50cwogIGdfZW1wdHlfd2VsbCA8LSBnZW9tX3BvaW50KGRhdGEgPSBlbXB0eV93ZWxsLCBhZXMoeCA9IENvbCwgeSA9IFJvdyksCiAgICBzaGFwZSA9IDEsIHNpemUgPSB3ZWxsX3NpemUsIGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BKQoKICBnX3BsYXRlIDwtIGdlb21fcG9pbnQoZGF0YSA9IHBsYXRlLCBhZXMoeCA9IENvbCwgeSA9IFJvdywgZmlsbCA9IEZpbGxMYWJlbCksCiAgICBwY2ggPSAyMSwgc2l6ZSA9IHdlbGxfc2l6ZSkKCgogICMgQW5ub3RhdGUgdGV4dCBmb3IgZmlsbAogIHBsYXRlX2ZpbGxfdGV4dCA8LSBwbGF0ZSAlPiUKICAgIGdyb3VwX2J5KEZpbGxMYWJlbCkgJT4lCiAgICBzdW1tYXJpemUoQ29sID0gbWVhbihDb2wpLCBSb3cgPSBtZWFuKFJvdykpICU+JQogICAgbXV0YXRlKFJvdyA9IGlmZWxzZSgoUm93ICUlIDEpID09IDAsIFJvdyAtIHZqdXN0LCBSb3cpKQoKICBpZiAoIlRleHRMYWJlbCIgJWluJSBuYW1lcyhkZikpIHsKICAgIGdfdGV4dF9sYWJlbCA8LSBnZW9tX3RleHQoZGF0YSA9IHBsYXRlLCBhZXMoeCA9IENvbCwgeSA9IFJvdywgbGFiZWwgPSBUZXh0TGFiZWwpLCBzaXplID0gdGV4dF9zaXplKQogIH0gZWxzZSBnX3RleHRfbGFiZWwgPC0gTlVMTAoKICBpZiAoYW5ub3RhdGlvbiA9PSBUKSB7CiAgICBnX3RleHRfZmlsbCA8LSBnZW9tX3RleHQoZGF0YSA9IHBsYXRlX2ZpbGxfdGV4dCwgYWVzKHggPSBDb2wsIHkgPSBSb3csIGxhYmVsID0gRmlsbExhYmVsKSkKICB9IGVsc2UgZ190ZXh0X2ZpbGwgPC0gTlVMTAoKCiAgIyBQbG90IHBsYXRlCiAgcHAgPC0KICAgIGdncGxvdCgpICsgZ19wbGF0ZSArIGdfZW1wdHlfd2VsbCArIGdfdGV4dF9sYWJlbCArIGdfdGV4dF9maWxsICsKICAgIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIiIsIGJyZWFrcyA9IDE6MTIsIGxhYmVscyA9IDE6MTIsIGxpbWl0cyA9IGMoMSwgMTIpLCBwb3NpdGlvbiA9ICJ0b3AiKSArCiAgICBzY2FsZV95X3JldmVyc2UobmFtZSA9ICIiLCBsaW0gPSBjKDgsIDEpLCBicmVha3MgPSAxOjgsIGxhYmVscyA9IExFVFRFUlNbMTo4XSkgKwogICAgdGhlbWVfYncoKSArCiAgICBOVUxMCgogIGlmIChmaWxsX2xlZ2VuZCA9PSBUKSB7CiAgICByZXR1cm4ocHArdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpKQogIH0gZWxzZSByZXR1cm4ocHAgKyBndWlkZXMoZmlsbD1GKSkKCn0KCmVhc3lfcGxvdF9wbGF0ZSA8LSBmdW5jdGlvbihwbGF0ZSkgewogIG11dGF0ZShwbGF0ZSwKICAgIFRleHRMYWJlbCA9IGlmZWxzZShNaXhJc29sYXRlLCBwYXN0ZShJc29sYXRlMSwgSXNvbGF0ZTIsIHNlcCA9ICJfIiksIElzb2xhdGUxKSwKICAgIEZpbGxMYWJlbCA9IHBhc3RlMChDb21tdW5pdHksIGlmZWxzZShNaXhJc29sYXRlLCAiIiwgIl9zaW5nbGUiKSkpICU+JQogICAgZHJhd19wbGF0ZV9mcm9tX2RmKCkKfQoKYGBgCgpgYGB7cn0KZm9yIChpIGluIDE6NykgYXNzaWduKHBhc3RlMCgicCIsIGkpLCBlYXN5X3Bsb3RfcGxhdGUoZXZhbChwYXJzZSh0ZXh0ID0gcGxhdGVzX25hbWVbaV0pKSkpCnAgPC0gcGxvdF9ncmlkKHAxLCBwMiwgcDMsIE5VTEwsIHA0LCBwNSwgcDYsIHA3LCBsYWJlbHMgPSBjKCJCMl85MzMiLCAiQjJfNDQ0IiwgIkNfQzExUjEiLCAiIiwgIkMyXzEzQSIsICJDMl8xM0IiLCAiRF83NSIsICJEXzU1NDMiKSwgbmNvbCA9IDIsIG5yb3cgPSA0KQpnZ3NhdmUoImZpZ3VyZS8wMkEtcGxhdGVfbGF5b3V0LnBkZiIsIHAsIHdpZHRoID0gMTIsIGhlaWdodCA9IDE2KQpgYGAKClBsYXRlIGxheW91dCB0aGF0IHRha2VzIGRpZmZlcmVudCBpbml0aWFsIGZyZXF1ZW5jaWVzOgoKLSBQMSBpcyA1MCU6NTAlLgoKLSBQMiBhbmQgUDMgYXJlIGlkZW50aWNhbCBhbmQgd2hvc2Ugcm93cyBhcmUgOTUlIGFuZCBjb2x1bW5zIGFyZSA1JS4KClRoZSBvbmx5IGV4Y2VwdGlvbiBpcyBwbGF0ZSBDMTFSMSBpbiBiYXRjaCBDLCB3aGljaCBvbmx5IGhhcyBvbmUgcGxhdGUuCgoKIyAwMkIgQ0FTRVUgc2FuZ2VyIHNlcXVlbmNpbmcKCi0gVG8gZGV0ZXJtaW5lIHRoZSByZWxhdGl2ZSBhYnVuZGFuY2Ugb2Ygb2YgYW1iaWd1b3VzIHBhaXJzIGluIGNvbXBldGl0aXZlIGFzc2F5cy4gCgotIFVzZSBDQVNFVSBwYWNrYWdlcyB0byBhbmFseXNlIHRoZSBTYW5nZXIgc2VxdWVuY2luZyBvZiBtaXh0dXJlIGN1bHR1cmUuCgotIFNhbmdlciBzZXF1ZW5jaW5nIHByb3RvY29sIHByZXBhcmF0aW9uLiBFeHBlcmltZW50YWwgcHJvdG9jb2wgZmlsZXMgYXJlIHNhdmVkIGluIGZvbGRlciBgb3V0cHV0L3Byb3RvY29sL2AKCmBgYHtyfQpsaXN0LmZpbGVzKGhlcmU6OmhlcmUoIm91dHB1dC9wcm90b2NvbCIpLCBwYXR0ZXJuID0gImNhc2V1IikKYGBgCgotIE9uY2Ugd2UgZ290IHRoZSBtaXh0dXJlIFNhbmdlciBzZXF1ZW5jZXMgYmFjaywgd2UgaW1wbGVtZW50IGFuYWx5c2lzIGJ5IHVzaW5nIGBDQVNFVWAgKENvbXBvc2l0aW9uYWwgYW5hbHlzaXMgYnkgU2FuZ2VyIGVsZWN0cm9waGVyb2dyYW0gdW5taXhpbmcpLCBhbiBSIHBhY2thZ2UgZGVzaWduZWQgZm9yIHF1YW50aWZ5aW5nIHJlbGF0aXZlIGFidW5kYW5jZSBvZiBTYW5nZXIgc2VxdWVuY2VzIG1peHR1cmUuIFtzb3VyY2UgY29kZV0oaHR0cHM6Ly9iaXRidWNrZXQub3JnL0RhdHRhTWFub3NoaS9jYXNldSkuIEluc3RhbGwgYENBU0VVYCBmcm9tIGJpdGJ1Y2tldC4KCi0gQ2hlY2sgb3V0IFtwYWNrYWdlIHZpZ25ldHRlXShodHRwczovL2h0bWxwcmV2aWV3LmdpdGh1Yi5pby8/aHR0cHM6Ly9iaXRidWNrZXQub3JnL2RhdHRhbWFub3NoaS9jYXNldS9yYXcvbWFzdGVyL2RvYy9DQVNFVV9WaWduZXR0ZS5odG1sKS4KCmBgYHtyLCBlY2hvID0gVFJVRSwgZXZhbCA9IEZBTFNFfQpkZXZ0b29sczo6aW5zdGFsbF9iaXRidWNrZXQoJ2RhdHRhbWFub3NoaS9jYXNldScpICMgSW5zdGFsbCBDQVNFVSBwYWNrYWdlCmxpYnJhcnkoQ0FTRVUpCmBgYAoKCiMjIFRlc3Qgb24gZXhhbXBsZSBkYXRhCgpUZXN0IHRoZSBleGFtcGxlIGNvZGUgYW5kIGRhdGEuCgpGaXQgU2FuZ2VyIHNlcXVlbmNlcyBvZiBhIG1peGVkIGN1bHR1cmUgb2YgZm91ciBzdHJhaW5zLiBUaGlzIHN0ZXAgbWF5IHRha2UgYSBmZXcgc2Vjb25kcy4KCmBgYHtyIGVjaG8gPSBULCBldmFsID0gRn0KbGlicmFyeShDQVNFVSkKZGF0YSgnZm91clN0cmFpbkV4cHQnKSAjIGxvYWQgYW4gZXhhbXBsZSBkYXRhc2V0CnJlc3VsdHMgPC0KICBmaXRTYW5nZXJNaXh0dXJlKG1peHR1cmU9Zm91clN0cmFpbkV4cHQkbWl4dHVyZSwgIyBtaXh0dXJlCiAgY29tcG9uZW50cyA9IGZvdXJTdHJhaW5FeHB0JGNvbXBvbmVudHMsICMgRm91ciBpbmRpdmlkdWFsIDE2UyBzZXF1ZW5jZXMKICB2ZXJib3NlPVRSVUUpCgpzYXZlKHJlc3VsdHMsIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhL3RlbXAvQ0FTRVVfdGVzdF9yZXN1bHRzMS5SZGF0YSIpKQpgYGAKCmBgYHtyIGV2YWwgPSBGfQpsb2FkKGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhL3RlbXAvQ0FTRVVfdGVzdF9yZXN1bHRzMS5SZGF0YSIpKQpwcmludChyZXN1bHRzKSAgICAgICAgICAgICAgICAgICAgICAjIHZpZXcgdGhlIHJlc3VsdHMKcGxvdChyZXN1bHRzKSAgICAgICAgICAgICAgICAgICAgICAgIyBwbG90IHRoZSBmaXQKc2FuZ2VyRml0RGlhZ25vc3RpY1Bsb3QocmVzdWx0cykgICAgIyBwbG90IGEgYnVuY2ggbW9yZSBkaWFnbm9zdGljcwpgYGAKCkZpdHRlZCBtaXh0dXJlIHNhbmdlciBlbGVjdHJvcGhlcm9ncmFtIG91dHB1dAoKYGBge3IgZXZhbCA9IEZ9Cm5hbWVzKHJlc3VsdHMpCmBgYAoKCgojIyBDQVNFVSBwaWxvdDEKClRoZSBwbGF0ZSBsYXlvdXQgb2YgUENSIHBsYXRlIGFuZCBsaXN0IG9mIHNhbXBsZXMgYXJlIHNwZWNpZmllZCBpbiBgb3V0cHV0L3Byb3RvY29sL3Byb3RvY29sXzIwMTkwODEzX1Nhbmdlcl9zZXFfcHJlcC5wZGZgLiAKCmBgYHtyfQpmcmVhZChoZXJlOjpoZXJlKCJvdXRwdXQvcHJvdG9jb2wvdGFiX2ZpZy9wcm90b2NvbF8yMDE5MDgxM19TYW5nZXJfc2VxX3ByZXAtZ2VuZXdpel90YWJsZS5jc3YiKSkKYGBgCgpUaGUgaXNvbGF0ZXMgdXNlZCBpbiB0aGlzIHJvdW5kIGlzIGZyb20gdGhlIGxpc3QgYmVsb3cuCgpJc29sYXRlICAgICAgICAgfCAgQ29kZSAgICAgfCAgVGF4YQotLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tfC0tLS0tLS0KQzExUjEgaXNvbGF0ZSAxIHwgQSAgICAgICAgIHwgUHNldWRvbW9uYXMKQzFSNyBpc29sYXRlIDIgIHwgQiAgICAgICAgIHwgUHNldWRvbW9uYXMKQzFSNyBpc29sYXRlIDEgIHwgQyAgICAgICAgIHwgRW50ZXJvYmFjdGVyCkMxUjcgaXNvbGF0ZSA3ICB8IEQgICAgICAgICB8IFJhb3VsdGVsbGEKVGFibGU6IGlzb2xhdGVzCgpSZWFkIHRyYWNlIG1hdHJpY2VzIGZvciBpc29sYXRlcyBhbmQgbWl4dHVyZXMKCmBgYHtyfQppZihydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJCLUNBU0VVX3Nhbmdlcl9zZXEtMDEtcGlsb3QxLlIiKQpgYGAKCgpgYGB7cn0KQ0FTRVVfcGlsb3QxIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9DQVNFVV9waWxvdDEuY3N2IikpCkNBU0VVX3BpbG90MQpgYGAKCgpQbG90IHRoZSBleHBlY3RlZCBpc29sYXRlIGZyZXF1ZW5jeSB2cy4gQ0FTRVUgcHJlZGljdGVkIGZyZXF1ZW5jeQoKYGBge3IgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aD0zfQpDQVNFVV9waWxvdDEgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL0NBU0VVX3BpbG90MS5jc3YiKSkKQ0FTRVVfcGlsb3QxX3AxIDwtIAogIENBU0VVX3BpbG90MSAlPiUKICBmaWx0ZXIoSXNvbGF0ZTEgIT0gIkIiLCBJc29sYXRlMiAhPSAiQiIpICU+JSAjIFdpdGhvdXQgQiBhbmQgCiAgbXV0YXRlKFRyZWF0bWVudCA9IGlmZWxzZShUcmVhdG1lbnQgPT0gIkFNIiwgImFtcGxpY29uIG1peHR1cmUiLCAiT0QgbWl4dHVyZSIpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBJc29sYXRlMUZyZXEsIHkgPSBJc29sYXRlMUZyZXFQcmVkaWN0ZWQsIGNvbG9yID0gVHJlYXRtZW50KSkgKwogIGdlb21faml0dGVyKHNpemUgPSAyKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtLjAxLCAuNikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtLjAxLCAuNikpICsKICBmYWNldF9ncmlkKElzb2xhdGUxIH4gSXNvbGF0ZTIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKwogIGxhYnMoeCA9ICJFeHBlY3RlZCBpc29sYXRlIGZyZXF1ZW5jeSIsIHkgPSAiQ0FTRVUgcHJlZGljdGVkIGlzb2xhdGUgZnJlcXVlbmN5IikKCkNBU0VVX3BpbG90MV9wMQpnZ3NhdmUoImZpZ3VyZS8wMkItQ0FTRVVfcGlsb3QxX2V4cGVjdGVkX3ZzX3ByZWRpY3RlZC5wbmciLCBDQVNFVV9waWxvdDFfcDEpCmBgYAoKCgoKIyMgQ0FTRVUgcGlsb3QyCgpUaGUgcGxhdGUgbGF5b3V0IG9mIFBDUiBwbGF0ZSBhbmQgbGlzdCBvZiBzYW1wbGVzIGFyZSBzcGVjaWZpZWQgaW4gYG91dHB1dC9wcm90b2NvbC9wcm90b2NvbF8yMDE5MDgxM19TYW5nZXJfc2VxX3ByZXAucGRmYC4gVGhlcmUgYXJlIDMyIHNhbXBsZXMgZnJvbSBwYWlyd2lzZSBjb21wZXRpdGlvbiBhbmQgMTYgc2FtcGxlcyBmcm9tIGNvbnRyb2wuIEFsc28gcmVhZCBTeWx2aWUncyBkYXRhLiAKCmBgYHtyIGluY2x1ZGUgPSBGfQpnZW5ld2l6X3BpbG90MiA8LSBmcmVhZChoZXJlOjpoZXJlKCJvdXRwdXQvcHJvdG9jb2wvdGFiX2ZpZy9wcm90b2NvbF8yMDE5MDkxMF9TYW5nZXJfc2VxX3ByZXAtZ2VuZXdpel90YWJsZV9DWUMuY3N2IikpIApnZW5ld2l6X3BpbG90MgpgYGAKCklzb2xhdGVzIEEgQiBDIEQgaW4gY29udHJvbCBhcmUgdGhlIGlzb2xhdGVzIGJlbG93LiAKCklzb2xhdGUgICAgICAgICB8ICBDb2RlICAgICB8ICBUYXhhCi0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18LS0tLS0tLQpDMTFSMSBpc29sYXRlIDEgfCBBICAgICAgICAgfCBQc2V1ZG9tb25hcwpDMVI3IGlzb2xhdGUgMiAgfCBCICAgICAgICAgfCBQc2V1ZG9tb25hcwpDMVI3IGlzb2xhdGUgMSAgfCBDICAgICAgICAgfCBFbnRlcm9iYWN0ZXIKQzFSNyBpc29sYXRlIDcgIHwgRCAgICAgICAgIHwgUmFvdWx0ZWxsYQoKYGBge3IgZXZhbCA9IEZ9CiMgRWFjaCBzY3JpcHQgdGFrZXMgfjEwIG1pbnMgdG8gcnVuCnNvdXJjZSgic2NyaXB0LzAyQi1DQVNFVV9zYW5nZXJfc2VxLTAyLXBpbG90Mi5SIikKI3NvdXJjZSgic2NyaXB0LzAyQi1DQVNFVV9zYW5nZXJfc2VxLTAzLXBpbG90Ml9TeWx2aWUuUiIpICMgUnVuIFN5bHZpZSdzIHNlcXVlbmNlCmBgYAoKCiMjIyBDb250cm9sIHBhaXJzCgpJbiB0aGUgMTIgY29udHJvbCBzeW50aGV0aWMgcGFpcnMgdGhhdCB3ZXJlIG1hZGUgb2YgNCBpc29sYXRlcywgY29tcGFyZSB0aGVzZSBwYWlycycgT0QgZnJlcXVlbmNpZXMsIGNvbG9ueSBjb3VudHMsIGFuZCBDQVNFVSBwcmVkaWN0aW9ucy4KClJlYWQgQ0FTRVUgcHJlZGljdGVkIGZyZXF1ZW5jaWVzIGFuZCBjb2xvbnkgY291bnQgZnJlcXVlbmNpZXMgaW4gdGhlIDEyIGNvbnRyb2wgcGFpcnMuCgpgYGB7cn0KIyBSZWFkIGRhdGEKQ0FTRVVfcGlsb3QyIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9DQVNFVV9waWxvdDIuY3N2IikpCkNBU0VVX3BpbG90Ml9wbGF0aW5nIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvcmF3L1Nhbmdlci9DQVNFVV9waWxvdDIvQ0FTRVVfcGlsb3QyX3BsYXRpbmcuY3N2IikpICU+JQogIG11dGF0ZShJc29sYXRlMUNvbG9ueUZyZXEgPSBJc29sYXRlMUNvbG9ueSAvIChJc29sYXRlMUNvbG9ueSArIElzb2xhdGUyQ29sb255KSwKICAgIElzb2xhdGUyQ29sb255RnJlcSA9IElzb2xhdGUyQ29sb255IC8gKElzb2xhdGUxQ29sb255ICsgSXNvbGF0ZTJDb2xvbnkpKQpgYGAKCkpvaW4gdGhlIENBU0VVIHByZWRpY3RlZCByZXN1bHQgb2YgY29udHJvbCBwYWlycyBpbiBgQ0FTRVVfcGlsb3QyYCB3aXRoIHRoZSBwbGF0aW5nIHJlc3VsdCBpbiBgQ0FTRVVfcGlsb3QyX3BsYXRpbmdgLiBUaGUgcGFpciBDWUNfY29udHJvbF81MF81MF9DRCBoYXMgYSBsb3QgY29sb25pZXMgYW5kIHRoZSBjb2xvbnkgY291bnQgb2YgQyBpcyBqdXN0IGFwcHJveGltYXRpb24gKG49MzAwKQoKYGBge3J9CkNBU0VVX3BpbG90Ml9jb250cm9sIDwtIENBU0VVX3BpbG90MiAlPiUKICBmaWx0ZXIoVHJlYXRtZW50ID09ICJjb250cm9sIikgJT4lCiAgbGVmdF9qb2luKENBU0VVX3BpbG90Ml9wbGF0aW5nLCBieSA9IGMoIk1peHR1cmVOYW1lIiwgIlVzZXIiLCAiVHJlYXRtZW50IiwgIklzb2xhdGUxRnJlcSIsICJJc29sYXRlMkZyZXEiLCAiSXNvbGF0ZTEiLCAiSXNvbGF0ZTIiKSkKYGBgCgpQbG90IHRoZSBDQVNFVSBwcmVkaWN0aW8gdnMuIGNvbG9ueSBjb3VudHMgYW5kIENBU0VVIHByZWRpY3Rpb24gdnMuIE9EIGZyZXF1ZW5jaWVzCgpgYGB7ciB3YXJuaW5nPUZ9CkNBU0VVX3BpbG90Ml9wMSA8LSAKICBDQVNFVV9waWxvdDJfY29udHJvbCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBJc29sYXRlMUNvbG9ueUZyZXEsIHkgPSBJc29sYXRlMUZyZXFQcmVkaWN0ZWQsIGNvbG9yID0gVHJlYXRtZW50KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbG9yID0gImJsYWNrIikgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC0uMDEsIDEuMDEpLCBicmVha3MgPSBjKDAsIDAuNSwgMSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtLjAxLCAxLjAxKSwgYnJlYWtzID0gYygwLCAwLjUsIDEpKSArCiAgZmFjZXRfZ3JpZChJc29sYXRlMSB+IElzb2xhdGUyKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpICsKICBsYWJzKHggPSAiRXhwZWN0ZWQgaXNvbGF0ZSBmcmVxdWVuY3kgYnkgY29sb255IGNvdW50aW5nIiwgCiAgICB5ID0gIkNBU0VVIHByZWRpY3RlZCBpc29sYXRlIGZyZXF1ZW5jeSIpICsKICBnZ3RpdGxlKCJDQVNFVSBwcmVkaWN0aW9uIHZzLiBDb2xvbnkgY291bnRzIikKCkNBU0VVX3BpbG90Ml9wMiA8LSAKICBDQVNFVV9waWxvdDJfY29udHJvbCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBJc29sYXRlMUZyZXEsIHkgPSBJc29sYXRlMUZyZXFQcmVkaWN0ZWQsIGNvbG9yID0gVHJlYXRtZW50KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbG9yID0gImJsYWNrIikgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC0uMDEsIDEuMDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLS4wMSwgMS4wMSkpICsKICBmYWNldF9ncmlkKElzb2xhdGUxIH4gSXNvbGF0ZTIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGxhYnMoeCA9ICJFeHBlY3RlZCBpc29sYXRlIGZyZXF1ZW5jeSBieSBPRCIsIAogICAgeSA9ICJDQVNFVSBwcmVkaWN0ZWQgaXNvbGF0ZSBmcmVxdWVuY3kiKSArCiAgZ2d0aXRsZSgiQ0FTRVUgcHJlZGljdGlvbiB2cy4gT0QgZnJlcXVlbmNpZXMiKQpgYGAKCgpgYGB7ciB3YXJuaW5nPUZ9CnAgPC0gcGxvdF9ncmlkKENBU0VVX3BpbG90Ml9wMSwgQ0FTRVVfcGlsb3QyX3AyLCBuY29sID0gMSkKZ2dzYXZlKCJmaWd1cmUvMDJCLUNBU0VVX3BpbG90Ml9jb250cm9sLnBuZyIsIHAsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMTApCmBgYAoKCgpgYGB7ciBldmFsID0gRiwgaW5jbHVkZSA9IEZ9CiMjIyBPdXRjb21lIG9mIHBhaXJ3aXNlIGNvbXBldGl0aW9uCiNUaGVyZSBhcmUgMjQgcGFpcnMgb2YgQzExUjEgYmVlbiBzZXF1ZW5jZWQgaW4gQ0FTRVUgcGlsb3QyLgppZiAoRkFMU0UpIHsKQ0FTRVVfcGlsb3QyIDwtIGZyZWFkKGhlcmU6OmhlcmUoImRhdGEvdGVtcC9DQVNFVV9waWxvdDIuY3N2IikpICU+JSAKICBmaWx0ZXIoVHJlYXRtZW50ID09ICJDMTFSMSIpICU+JQogIG11dGF0ZShDb21tdW5pdHkgPSBUcmVhdG1lbnQpICU+JQogIHNlbGVjdChDb21tdW5pdHksIElzb2xhdGUxLCBJc29sYXRlMiwgSXNvbGF0ZTFGcmVxLCBJc29sYXRlMkZyZXEsIElzb2xhdGUxRnJlcVByZWRpY3RlZCwgSXNvbGF0ZTJGcmVxUHJlZGljdGVkKSAlPiUKICBpbnZuZXQ6OnN3aXRjaF9wYWlyd2lzZV9jb2x1bW4oKQoKQ0FTRVVfcGlsb3QyICU+JSAKICBtdXRhdGUoUGFpciA9IHBhc3RlMChJc29sYXRlMSwgIl8iLCBJc29sYXRlMikpICU+JQogIGdncGxvdChhZXMoeCA9IElzb2xhdGUxRnJlcSwgeSA9IElzb2xhdGUxRnJlcVByZWRpY3RlZCwgY29sb3IgPSBQYWlyLCBHcm91cCA9IFBhaXIpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9saW5lKCkgKwojICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbG9yID0gImJsYWNrIikgKwogIGZhY2V0X3dyYXAoLn5Db21tdW5pdHkpICsKICB0aGVtZV9idygpCiAgICAKfQpgYGAKCgojIyBDQVNFVSBwaWxvdDMKClRoZSBwbGF0ZSBsYXlvdXQgb2YgUENSIHBsYXRlIGFuZCBsaXN0IG9mIHNhbXBsZXMgYXJlIHNwZWNpZmllZCBpbiBgb3V0cHV0L3Byb3RvY29sL3Byb3RvY29sXzIwMTkwOTIzX1NlcXVhbFByZXBfU2FuZ2VyX3ByZXAucGRmYC4gCgpgYGB7cn0KZnJlYWQoaGVyZTo6aGVyZSgib3V0cHV0L3Byb3RvY29sL3RhYl9maWcvcHJvdG9jb2xfMjAxOTA5MjRfU2FuZ2VyX3NlcV9wcmVwLWdlbmV3aXpfdGFibGVfQ1lDLmNzdiIpKQpgYGAKClJlYWQgdHJhY2UgbWF0cmljZXMgZm9yIGlzb2xhdGVzIGFuZCBtaXh0dXJlcwoKYGBge3IgZXZhbCA9IEZ9CiMgSXQgdGFrZXMgYWJvdXQgfjE1IG1pbnMgdG8gcnVuIAppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQi1DQVNFVV9zYW5nZXJfc2VxLTA0LXBpbG90My5SIikKYGBgCgpgYGB7cn0KQ0FTRVVfcGlsb3QzIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9DQVNFVV9waWxvdDMuY3N2IikpCkNBU0VVX3BpbG90MyAlPiUKICBtdXRhdGUoSXNvbGF0ZTEgPSBmYWN0b3IoSXNvbGF0ZTEpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBJc29sYXRlMUZyZXEsIHkgPSBJc29sYXRlMUZyZXFQcmVkaWN0ZWQsIGNvbG9yID0gSXNvbGF0ZTEsIGdyb3VwID0gcGFzdGUwKElzb2xhdGUxLCAiXyIsIElzb2xhdGUyKSkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX2xpbmUoKSArCiMgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiYmxhY2siKSArCiAgZmFjZXRfd3JhcCgufkNvbW11bml0eSkgKwogIHRoZW1lX2J3KCkKYGBgCgoKIyMgQ0FTRVUgcGlsb3Q0CgpUaGUgcGxhdGUgbGF5b3V0IG9mIFBDUiBwbGF0ZSBhbmQgbGlzdCBvZiBzYW1wbGVzIGFyZSBzcGVjaWZpZWQgaW4gYG91dHB1dC9wcm90b2NvbC9wcm90b2NvbF8yMDE5MTAwN19TYW5nZXJfc2VxX3ByZXAucGRmYC4gCgpgYGB7cn0KZnJlYWQoaGVyZTo6aGVyZSgib3V0cHV0L3Byb3RvY29sL3RhYl9maWcvcHJvdG9jb2xfMjAxOTEwMDdfU2FuZ2VyX3NlcV9wcmVwLWdlbmV3aXpfdGFibGVfQ1lDLmNzdiIpKQpgYGAKClJlYWQgdHJhY2UgbWF0cmljZXMgZm9yIGlzb2xhdGVzIGFuZCBtaXh0dXJlcwoKYGBge3IgZXZhbCA9IEZ9CiMgSXQgdGFrZXMgYWJvdXQgfjE1IG1pbnMgdG8gcnVuCmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJCLUNBU0VVX3Nhbmdlcl9zZXEtMDUtcGlsb3Q0LlIiKQpgYGAKCgpgYGB7cn0KQ0FTRVVfcGlsb3Q0IDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9DQVNFVV9waWxvdDQuY3N2IikpCkNBU0VVX3BpbG90NCAlPiUKICBtdXRhdGUoSXNvbGF0ZTEgPSBmYWN0b3IoSXNvbGF0ZTEpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBJc29sYXRlMUZyZXEsIHkgPSBJc29sYXRlMUZyZXFQcmVkaWN0ZWQsIGNvbG9yID0gSXNvbGF0ZTEsIGdyb3VwID0gcGFzdGUwKElzb2xhdGUxLCAiXyIsIElzb2xhdGUyKSkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCgufkNvbW11bml0eSkgKwogIHRoZW1lX2J3KCkKYGBgCgoKCiMgMDJDIHBhaXJzX09EX0NGVQoKLSBFcnJvciBwcm9wYWdhdGlvbiB0aGVvcnkKCi0gRGVyaXZlIGlzb2xhdGVzJyAkXGVwc2lsb24kIGZyb20gVDggZGF0YSBhbmQgY2FsY3VsYXRlIHVuY2VydGF0aW50eSB1c2luZyBlcnJvciBwcm9wYWdhdGlvbiB0aGVvcnkKCi0gQ29udmVydCBUMCBPRCBmcmVxdWVuY3kgJGZeTyQgdG8gQ0ZVIGZyZXF1ZW5jeSAkZl5DJCBhbmQgZXN0aW1hdGUgdGhlIHVuY2VydGFpbnR5IGluIGNvbnZlcnRlZCBDRlUgZnJlcXVlbmNpZXMgYXQgVDguIE91dHB1dCBgZGF0YS90ZW1wL3BhaXJzX0NGVV9mcmVxX3VuY2VydGFpbnR5LmNzdmAKCiMjIEdlbmVyYWwgZm9ybXVsYSBvZiBlcnJvciBwcm9wYWdhdGlvbgoKVGhpcyBzZWN0aW9uIGV4cGxhaW5zIHRoZSBlcnJvciBwcm9wYWdhdGlvbiB0aGVvcnkgdG8gZXN0aW1hdGUgdGhlIHVuY2VydGFpbnR5IGluIHRoZSBleHBlcmltZW50YWwgbWVhc3VyZW1lbnQuIFRoZXJlIGFyZSBvbmUgb3IgbW9yZSBxdWFudGl0aWVzICR4LCB5LCAuLi4kLCB3aXRoIGNvcnJlc3BvbmRpbmcgdW5jZXJ0YWludGllcyAkXGRlbHRhIHgsIFxkZWx0YSB5LCAuLi4kIGFuZCB0aGF0IHdlIHdpc2ggdG8gdXNlIHRoZSBtZWFzdXJlZCB2YWx1ZXMgb2YgeCBhbmQgeSB0byBjYWxjdWxhdGUgdGhlIHF1YW50aXR5IG9mIHJlYWwgaW50ZXJlc3QgcS4gVGhlcmUgYXJlIHRocmVlIHByb3Zpc2lvbmFsIHJ1bGVzOgoKMS4gVGhlIHNxdWFyZS1yb290IHJ1bGUgZm9yIGNvdW50aW5nIGV4cGVyaW1lbnRzLiBUaGUgYXZlcmFnZSBudW1iZXIgb2YgZXZlbnQgaW4gdGltZSBUIGlzICR2XHBtXHNxcnR7dn0kCgoyLiBVbmNlcnRhaW50eSBpbiAqKnN1bXMgYW5kIGRpZmZlcmVuY2VzKiouIFRoZSBjb21wdXRlZCBtZWFuIHZhbHVlICRxPXgreSt6LSh1K3cpJC4gSWYgdGhlIHVuY2VydGFpbnRpZXMgaW4geCwgLi4uLCB3IGFyZSBrbm93biB0byBiZSBpbmRlcGVuZGVudCBhbmQgcmFuZG9tLCB0aGVuIHRoZSB1bmNlcnRhaW50eSBpbiB0aGUgY29tcHV0ZWQgdmFsdWUgb2YgcSBpcyB0aGUgcXVhZHJhdGljIHN1bSAkXGRlbHRhIHEgPSBcc3FydHsoXGRlbHRhIHgpXjIrKFxkZWx0YSB5KV4yKyhcZGVsdGEgeileMisoXGRlbHRhIHUpXjIrKFxkZWx0YSB3KV4yfSQgLCBJbiBhbnkgY2FzZSwgJFxkZWx0YSBxJCBpcyBuZXZlciBsYXJnZXIgdGhhbiB0aGVpciBvcmRpbmFyeSBzdW0gJFxkZWx0YSBxIFxsZXFzbGFudCBcZGVsdGEgeCArIFxkZWx0YSB5KyBcZGVsdGEgeiArIFxkZWx0YSB1ICsgXGRlbHRhIHckCgozLiBVbmNlcnRhaW50eSBpbiAqKnByb2R1Y3QgYW5kIHF1b3RpZW50cyoqLiAkcT1cZnJhY3t4XHRpbWVzIHp9e3VcdGltZXMgd30kLCB0aGVuIHRoZSBmcmFjdGlvbmFsIHVuY2VydGFpbnR5IGluIHRoZSBjb21wdXRlZCB2YWx1ZSBxIGlzIHRoZSBzdW0uIElmIHRoZSB1bmNlcnRhaW50aWVzIGluIHgsIC4uLix3IGFyZSBpbmRlcGVuZGVudCBhbmQgcmFuZG9tLCB0aGVuIHRoZSBmcmFjdGlvbmFsIHVuY2VydGFpbnR5IGluIHEgaXMgdGhlIHN1bSBpbiBxdWFkcmF0dXJlIG9mIHRoZSBvcmlnaW5hbCB1bmNlcnRhaW50aWVzLCAkXGZyYWN7XGRlbHRhIHF9e1xsZWZ0fHFccmlnaHR8fSA9IFxzcXJ0eyhcZnJhY3tcZGVsdGEgeH17XGxlZnR8eFxyaWdodHx9KV4yICsgXGZyYWN7XGRlbHRhIHl9e1xsZWZ0fHlccmlnaHR8fSleMiArXGZyYWN7XGRlbHRhIHp9e1xsZWZ0fHpccmlnaHR8fSleMiArXGZyYWN7XGRlbHRhIHV9e1xsZWZ0fHVccmlnaHR8fSleMiArIFxmcmFje1xkZWx0YSB3fXtcbGVmdHx3XHJpZ2h0fH0pXjJ9JC4gJFxmcmFje1xkZWx0YSBxfXtcbGVmdHwgcSBccmlnaHR8fSBcbGVxc2xhbnQgXGZyYWN7XGRlbHRhIHh9e1xsZWZ0fCB4IFxyaWdodHx9ICsgXGZyYWN7XGRlbHRhIHp9e1xsZWZ0fCB6IFxyaWdodHx9ICsgXGZyYWN7XGRlbHRhIHV9e1xsZWZ0fCB1IFxyaWdodHx9ICsgXGZyYWN7XGRlbHRhIHd9e1xsZWZ0fCB3IFxyaWdodHx9JCAKClRha2luZyB0aGVzZSB0aHJlZSBwcm92aXNpb25hbCBydWxlcyB0b2dldGhlciwgdGhlIGdlbmVyYWwgZm9ybXVsYSBmb3IgZXJyb3IgcHJvcGFnYXRpb24gdGFrZXMgdGhlIGZvbGxvd2luZyBmb3JtLiBBc3N1bWUgdGhlIGNvbXB1dGVkIHF1YW50aXR5IGlzIGEgZnVuY3Rpb24gb2YgJHhfMSwgeF8yLCAuLi4sIHhfbiQsIHRoZSB1bmNlcnRhaW50eSBpbiBxIGlzICQkXGRlbHRhIHE9IFxzcXJ0eyhcc3Vte1xmcmFje1xwYXJ0aWFsIHF9e1xwYXJ0aWFsIHhfaX19XGRlbHRhIHhfaSleMn0kJCAKCgoKIyMgVW5jZXJ0YWludHkgaW4gZXBzaWxvbiAKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQy1wYWlyc19PRF9DRlUtMDEtZXBzaWxvbl91bmNlcnRhaW50eS5SIikKYGBgCgoKVGhlIHVuY2VydGFpbnRpZXMgaW4gZWFjaCBpc29sYXRlJyBlcHNpbG9uICRcZXBzaWxvbl9BID0gXGZyYWN7T0RfQSBERl9BIHZfQX17Q0ZVX0F9JCBjb21lcyBmcm9tIGZvdXIgcGFydHM6CgoxLiAkREYkOiBEaWx1dGlvbiBmYWN0b3JzLiBUaGUgdW5jZXJ0YWludHkgY29tZXMgZnJvbSB0aGUgcGlwZXR0aW5nIGluIHNlcmlhbCBkaWx1dGlvbiwgd2hpY2ggaXMgY2FsY2F1bHRlZCBiZWxvdy4KMi4gJHYkOiBQbGF0aW5nIHZvbHVtZXMuIFRoZSBzeXN0ZW1hdGljIGVycm9yIGZvciBQMjAgc2V0IGF0IDIwIHVMIGlzIDAuNCB1TC4KMy4gJENGVSQ6IENGVSBjb3VudHMuIFRoZSB1bmNlcnRhaW50eSBpbiBDRlUgZm9sbG93cyBwb2lzc29uIGRpc3RyaWJ1dGlvbiwgd2hpY2ggbWVhbnMgdGhhdCB0aGUgdmFyaWFuY2UgaXMgdGhlIHNhbWUgYXMgdGhlIG1lYW4gKG1lYXN1cmVkIENGVSkuIFRoZSBzdGFuZGFyZCBkZXZpYXRpb24gaXMgJFxzcXJ0e0NGVX0kLgo0LiAkT0QkOiBPRCBtZWFzdXJlbWVudC4gVGhlIHVuY2VydGFpbnR5IGluIG1lYXN1cmluZyBPRCBpbiBwbGF0ZSByZWFkZXIsIHdoaWNoIGlzIGFzc3VtZWQgdG8gYmUgMC4wMDEuCgoKKipEaWx1dGlvbiBmYWN0b3IqKgoKVGhlIHVuY2VydGFpbnR5IGluIGRpbHV0aW9uIGZhY3RvciBjb21lcyBmcm9tIHRoZSBwaXBldHRpbmcgc3RlcHMgaW4gc2VyaWFsIGRpbHV0aW9uLCB3aGljaCBpbmNsdWRlIHR3byBwaXBldHRpbmcgdm9sdW1lczoKCjEuIGBWMWA6IHNlcmlhbCBkaXNwZW5zaW5nIDEwIHVMIG9mIGRpbHV0ZWQgc29sdXRpb24gdXNpbmcgbVAyMC4gSXQgaGFzIHVuY2VydGFpbnR5IGBFcnJvclYxYCAyIHVMLgoyLiBgVjJgOiBkaXNwZW5zZSA5MCB1TCBvZiBQQlMgdXNpbmcgbVAyMDAuIEl0IGhhcyB1bmNlcnRhaW50eSBgRXJyb3JWMmAgMC40IHVMLgoKRm9yIGRpbHV0aW9uIGZhY3RvciAkMTBee259JCwgaXQgaGFzIHRoZSB0aGUgbWVhbiAkKFxmcmFje1ZfMX17Vl8xK1ZfMn0pXm4kLiBUbyBvYnRhaW4gdGhlIHVuY2VydGFpbnR5IGluIHRoZSBtZWFzdXJlZCBtZWFuLCBmaXJzdCB3ZSBjYWx1Y3VsYXRlIHRoZSBwYXJ0aWFsIGRlcml2YXRpdmVzICRcZnJhY3tccGFydGlhbCBERn17XHBhcnRpYWwgVl8xfSQgYW5kICRcZnJhY3tccGFydGlhbCBERn17XHBhcnRpYWwgVl8yfSQuIFRoZW4gdGhlIHVuY2VydGFpbnR5ICRcZGVsdGEgREYgPSBcc3FydHsoXGZyYWN7XHBhcnRpYWwgREZ9e1xwYXJ0aWFsIFZfMX1cZGVsdGEgVl8xKV4yICsgKFxmcmFje1xwYXJ0aWFsIERGfXtccGFydGlhbCBWXzJ9XGRlbHRhIFZfMileMn0kCgoKYGBge3J9CmRpbHV0aW9uX2ZhY3RvciA8LSAKICBkYXRhLmZyYW1lKG4gPSBjKDQsIDUpLCBWMSA9IDEwLCBWMiA9IDkwLCBFcnJvclYxID0gMC40LCBFcnJvclYyID0gMikgJT4lCiAgbXV0YXRlKFBhcnRpYWxWMSA9IG4gKiBWMV4obi0xKSAqIFYyIC8gKFYxK1YyKV4obisxKSwgIy1uKihWMStWMileKG4tMSkqVjIvKFYxXihuKzEpKSwKICAgICAgICAgUGFydGlhbFYyID0gLW4gKiBWMV4obi0xKSAvIChWMStWMileKG4rMSksICNuKihWMStWMileKG4tMSkvKFYxXm4pLAogICAgICAgICBERiA9IChWMS8oVjErVjIpKV5uLAogICAgICAgICBFcnJvckRGID0gc3FydCgoUGFydGlhbFYxKkVycm9yVjEpXjIgKyAoUGFydGlhbFYyKkVycm9yVjIpXjIpKQoKZGlsdXRpb25fZmFjdG9yCmBgYAoKCkJ5IHVzaW5nIGVycm9yIHByb3BhZ2F0aW9uIHRoZXJveSwgdGhlIHVuY2VydGFpbnR5IGluIGlzb2xhdGVzIGVwc2lsb24gaGFzIHRoZSBmb3JtIAoKJCRcZGVsdGEgXGVwc2lsb24gPSBcc3FydHsoXGZyYWN7XHBhcnRpYWwgIFxlcHNpbG9ufXtccGFydGlhbCBERn1cZGVsdGEgREYpXjIgKyhcZnJhY3tccGFydGlhbCAgXGVwc2lsb259e1xwYXJ0aWFsIENGVX1cZGVsdGEgQ0ZVKV4yICsgKFxmcmFje1xwYXJ0aWFsICBcZXBzaWxvbn17XHBhcnRpYWwgT0R9XGRlbHRhIE9EKV4yICsgKFxmcmFje1xwYXJ0aWFsICBcZXBzaWxvbn17XHBhcnRpYWwgVn1cZGVsdGEgVileMn0kJAoKCmBgYHtyfQppc29sYXRlc19lcHNpbG9uX3VuY2VydGFpbnR5IDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9pc29sYXRlc19lcHNpbG9uX3VuY2VydGFpbnR5LmNzdiIpKQppc29sYXRlc19lcHNpbG9uX3VuY2VydGFpbnR5CmBgYAoKVGhlcmUgYXJlIDcgaXNvbGF0ZXMgdGhhdCBoYXZlIGVpdGhlciAwIENGVSBvciBuZWdhdGl2ZSBPRCB2YWx1ZSwgc28gdGhleSBkb24ndCBoYXZlIGVwc2lsb24gdmFsdWVzLgoKYGBge3J9Cmlzb2xhdGVzX2Vwc2lsb25fdW5jZXJ0YWludHkgJT4lCiAgZmlsdGVyKGlzLm5hKEVwc2lsb24pKQpgYGAKCiMjIENvbnZlcnQgVDAgT0QgZnJlcXVlbmNpZXMgdG8gQ0ZVIGZyZXF1ZW5jaWVzCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkMtcGFpcnNfT0RfQ0ZVLTAyLUNGVV9mcmVxdWVuY3kuUiIpCmBgYAoKVGhlIG91dGNvbWUgb2YgcGFpcndpc2UgY29tcGV0aXRpb24gd2VyZSBkZXRlcm1pbmVkIGJ5IGNvbXBhcmluZyB0aGUgZnJlcXVlbmN5IGNoYW5nZXMgYmV0d2VlbiBUMCBhbmQgVDguIFRoZSBUOCBmcmVxdWVuY2llcyB3ZXJlIGRldGVybWluZWQgYnkgcGxhdGluZyB0aGUgbWF0dXJlIG1lZGlhIG9uIHJpY2ggYWdhciBtZWRpYSBvbiB3aGljaCB0aGUgY29sb25pZXMgd2VyZSBjb3VudGVkLCB3aGVyZWFzIFQwIGZyZXF1ZW5jaWVzIHdlcmUgc2V0IHRvIDk1LzUsIDUwLzUwIGFuZCA1Lzk1IGJ5IG1peGluZyB0d28gaXNvbGF0ZSBpbm9jdWxhIHdpdGggZXF1YWwgT0QuICBJbiB0aGlzIHNlY3Rpb24sIEkgd2lsbCB1c2UgdGhlIE9ELUNGVSBjb252ZXJzaW9uIGNvZWZmaWNpZW50ICRcZXBzaWxvbiQgZGVyaXZlZCBmcm9tIFQ4IGlzb2xhdGUgZGF0YSB0byBjb252ZXJ0IFQwIE9EIGZyZXF1ZW5jaWVzIGludG8gQ0ZVIGZyZXF1ZW5jaWVzLiBJbiBzcGVjaWZpYywgdGhlIENGVSBmcmVxdWVuY3kgb2YgaXNvbGF0ZSAxICRmXkNfMSQgb2YgYSBwYWlyIGNhbiBiZSBkZXJpdmVkIGZyb20gT0QgZnJlcXVlbmNpZXMgb2YgaXNvbGF0ZSAxIGFuZCAyICRmXk9fMSAsZl5PXzIkLCB3aGljaCBoYXZlIHRoZSByZWxhdGlvbnNoaXAgYmVsb3cuIAoKJGZeQ18xID0gXGZyYWN7Zl5vXzFcZXBzaWxvbl8xREZ2fXtmXm9fMVxlcHNpbG9uXzFERnYgKyBmXm9fMlxlcHNpbG9uXzJERnZ9PVxmcmFje2Zeb18xXGVwc2lsb25fMX17Zl5vXzFcZXBzaWxvbl8xICsgZl5vXzJcZXBzaWxvbl8yfSQKCndoZXJlICRcZXBzaWxvbiQgb2YgZWFjaCBpc29sYXRlIHdhcyBwcmUtY2FsY3VsYXRlZCBmcm9tIFQ4IGRhdGFzZXQuIERGIGFuZCB2IGFyZSB0aGUgc2FtZSBpbiBjb252ZXJzaW9uLgoKYGBge3J9CnBhaXJzX0NGVV9mcmVxIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wYWlyc19DRlVfZnJlcS5jc3YiKSkKcGFpcnNfQ0ZVX2ZyZXEKYGBgCgoKIyMgVW5jZXJ0YWludHkgaW4gVDAgQ0ZVIGZyZXF1ZW5jaWVzCgpgYGB7ciB3YXJuaW5nID0gRn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkMtcGFpcnNfT0RfQ0ZVLTAzLUNGVV9mcmVxdWVuY3lfdW5jZXJ0YWludHkuUiIpCmBgYAoKV3JpdGUgQ0ZVIGZyZXF1ZW5jaWVzIHRvIGBkYXRhL3RlbXAvcGFpcnNfQ0ZVX2ZyZXFfdW5jZXJ0YWludHkuY3N2YAoKYGBge3J9CnBhaXJzX0NGVV9mcmVxX3VuY2VydGFpbnR5IDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wYWlyc19DRlVfZnJlcV91bmNlcnRhaW50eS5jc3YiKSkKcGFpcnNfQ0ZVX2ZyZXFfdW5jZXJ0YWludHkKYGBgCgoKIyAwMkQgZGV0ZXJtaW5lIHBhaXJ3aXNlIGludGVyYWN0aW9uCgojIyBDb21iaW5lIG91dGNvbWVzIG9mIHBhaXJ3aXNlIGNvbXBldGl0aW9uIGZyb20gQ0ZVIGNvdW50cyBhbmQgQ0FTRVUKClJhdyBkYXRhIChlLmcuLCBDRlUgY291bnRzIGFuZCBDQVNFVSBTYW5nZXIgc2VxdWVuY2VzKSBhcmUgcHJvY2Vzc2VkIGFuZCBnZW5lcmF0ZWQgaW50byB0ZW1wb3JhcnkgcmVzdWx0IGNzdjoKCjEuIGAwMkItQ0FTRVVfc2FuZ2VyX3NlcWAgcmVhZHMgQ0FTRVUgcmF3IGRhdGEgYW5kIG91dHB1dHMgYHRlbXAvQ0FTRVVfcGlsb3QyLmNzdmAgYW5kIGB0ZW1wL0NBU0VVX3BpbG90My5jc3ZgLiBCb3RoIGZpbGVzIGFyZSBDQVNFVSBwcmVkaWN0ZWQgVDggZnJlcXVlbmNpZXMuCgoyLiBgMDJDLXBhaXJzX09EX0NGVWAgcmVhZHMgcGFpcl9jb21wZXRpdGlvbiBhbmQgZGlsdXRpb24gZmFjdG9yIGRhdGEsIGFuZCBpdCBvdXRwdXRzIGB0ZW1wL3BhaXJzX0NGVV9mcmVxX3VuY2VydGFpbnR5LmNzdmAsIHdoaWNoIGhhcyB0aGUgVDAgT0QtY29udmVydGVkIENGVSBmcmVxdWVuY2llcyBhbmQgVDggQ0ZVIGZyZXF1ZW5jaWVzIHdpdGggdW5jZXJ0YWludGllcy4KCioqTm90ZSB0aGF0IGlmIGEgcGFpciBoYXMgYm90aCBDRlUgYW5kIENBU0VVIHJlc3VsdCwgQ0FTRVUgd2lsbCBvdmVyd3JpdGUgdGhlIENGVSByZXN1bHQqKgoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJELWRldGVybWluZV9wYWlyd2lzZV9pbnRlcmFjdGlvbi0wMS1jb21iaW5lX0NGVV9DQVNFVV9yZXN1bHQuUiIpCmBgYAoKVGhlIHNjcmlwdCBpbiB0aGlzIHNlY3Rpb24gcmV0dXJucyBhIGRhdGEuZnJhbWUgYHBhaXJzX2ZyZXFgIHRoYXQgaGFzIHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzOgoKLSBgQ29tbXVuaXR5YAotIGBJc29sYXRlMWAgYW5kIGBJc29sYXRlMmA6IGluZGljZXMgb2YgaXNvbGF0ZXMgd2l0aGluIGEgY29tbXVuaXR5LiBUaGUgbnVtYmVyIG9mIGlzb2xhdGUxIGlzIGFsd2F5cyBzbWFsbGVyIHRoYW4gaXNvbGF0ZTIKLSBgSXNvbGF0ZTFJbml0aWFsT0RGcmVxYCBhbmQgYElzb2xhdGUySW5pdGlhbE9ERnJlcWA6IDUsIDUwIG9yIDk1LiBUaGUgaW5pdGlhbCBPRCBmcmVxdWVuY2llcyBvZiBpc29sYXRlcyBhdCBUMC4gVGhpcyB0d28gc2VydmUgYXMgZGlzY3JldGUgZ3JvdXBpbmcgdmFyaWFibGVzLgotIGBUaW1lYDogVDAgb3IgVDguCi0gYElzb2xhdGUxTWVhc3VyZWRGcmVxYDogdGhlIG1lYXN1cmVkIGZyZXF1ZW5jeSBvZCBpc29sYXRlMSBpbiB0aGUgcGFpci4gCi0gYEVycm9ySXNvbGF0ZTFNZWFzdXJlZEZyZXFgOiB0aGUgdW5jZXJ0YWludHkgb2YgYElzb2xhdGUxTWVhc3VyZWRGcmVxYC4KLSBgUmF3RGF0YVR5cGVgOiBPRCwgT0R0b0NGVSwgQ0ZVLCBTYW5nZXIgKENBU0VVKS4gVGhlIHJhdyBkYXRhIHR5cGUgaW4gd2hpY2ggdGhlIGlzb2xhdGUgZnJlcXVlbmNpZXMgd2VyZSBtZWFzdXJlZC4KLSBgQ29udGFtaW5hdGlvbmA6IGxvZ2ljYWwuIFRoZXJlIGFyZSBjb250YW1pbmF0aW9ucyBpbiB0aHJlZSBwYWlycyBhdCBUOCBwbGF0ZXMuCgoxODZ4M3gyPTExMTYgcGFpci1mcmVxIGF0IHR3byB0aW1lIHBvaW50cwoKYGBge3J9CnBhaXJzX2ZyZXEgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvcGFpcnNfZnJlcS5jc3YiKSkKcGFpcnNfZnJlcQpgYGAKCgpUaGVyZSBpcyBvbmUgcGFpci1mcmVxIHRoYXQgY2Fubm90IGJlIHNwZWNpZmllZCBiZWNhdXNlIG9mIGNvbnRhbWluYXRpb24uCgpgYGB7cn0KcGFpcnNfZnJlcSAlPiUKICBmaWx0ZXIoVGltZSA9PSAiVDgiKSAlPiUKICBmaWx0ZXIoaXMubmEoSXNvbGF0ZTFNZWFzdXJlZEZyZXEpKQpgYGAKCgojIyBEZXRlcm1pbmUgcGFpcndpc2UgaW50ZXJhY3Rpb25zCgpgYGB7ciB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJELWRldGVybWluZV9wYWlyd2lzZV9pbnRlcmFjdGlvbi0wMi1kZXRlcm1pbmVfcGFpcndpc2VfaW50ZXJhY3Rpb24uUiIpCmBgYAoKClBsb3QgZnJlcXVlbmN5IGNoYW5nZXMuIE91dHB1dCBmaWd1cmUgb2YgQ0ZVIGZyZXF1ZW5jeSBjaGFuZ2VzIHRvIGBvdXRwdXQvZmlndXJlL3BhaXJzX2ZyZXFfY2hhbmdlX3VuY2VydGFpbnR5LnBkZmAKCmBgYHtyIGV2YWwgPSBGfQpsb2FkKGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wX3BhaXJzX2ZyZXFfY2hhbmdlX2xpc3QuUmRhdGEiKSkKcGRmKGhlcmU6OmhlcmUoIm91dHB1dC9yZXBvcnQvZmlndXJlLzAyRC1mcmVxX2NoYW5nZV91bmNlcnRhaW50eS5wZGYiKSwgaGVpZ2h0ID0gMTAgLCB3aWR0aCA9IDEwKTsgZm9yIChpIGluIDE6bGVuZ3RoKGNvbW11bml0aWVzJENvbW11bml0eSkpIHByaW50KHBfcGFpcnNfZnJlcV9jaGFuZ2VfbGlzdFtbaV1dKTsgaW52aXNpYmxlKGRldi5vZmYoKSkKYGBgCgpUYWJsZSBvZiBhbGwgMjcgcG9zc2libGUgY29tYmluYXRpb25zIG9mIGZpdG5lc3MgZnVuY3Rpb24gYW5kIHRoZWlyIGludGVyYWN0aW9uIHR5cGVzIAoKYGBge3J9CmludGVyYWN0aW9uX3R5cGUgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL2ludGVyYWN0aW9uX3R5cGUuY3N2IikpCmludGVyYWN0aW9uX3R5cGUKYGBgCgoKVGFibGUgb2YgaW50ZXJhY3Rpb24gdHlwZXMKCmBgYHtyfQpwYWlyc19pbnRlcmFjdGlvbl9maXRuZXNzIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wYWlyc19pbnRlcmFjdGlvbl9maXRuZXNzLmNzdiIpKQpwYWlyc19pbnRlcmFjdGlvbl9maXRuZXNzICU+JQogIGdyb3VwX2J5KEludGVyYWN0aW9uVHlwZSkgJT4lCiAgc3VtbWFyaXplKENvdW50ID0gbigpKSAKYGBgCgpJbnRlcmFjdGlvbiB0YWJsZQoKYGBge3J9CnBhaXJzX2ludGVyYWN0aW9uX3RhYmxlIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wYWlyc19pbnRlcmFjdGlvbl90YWJsZS5jc3YiKSkKcGFpcnNfaW50ZXJhY3Rpb25fdGFibGUKYGBgCgoKIyMgSXNvbGF0ZSB0b3VybmFtZW50CgoKYGBge3Igd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyRC1kZXRlcm1pbmVfcGFpcndpc2VfaW50ZXJhY3Rpb24tMDMtaXNvbGF0ZV90b3VybmFtZW50LlIiKQpgYGAKClRvdXJuYW1lbnQgcmFua3Mgb2YgZWFjaCBpc29sYXRlLiBOb3RlIHRoYXQgSSBjb25zaWRlciBuZXR1cmFsaXR5IGFuZCBiaXN0YWJpbGl0eSBhcyBkcmF3IGluIHRoZSB0b3VybmFtZW50LgoKLSBgU2NvcmVgOiB0aGUgY29tcGV0aXRpdmUgc2NvcmVzIG9mIGlzb2xhdGUuIFRoaXMgc2NvcmUgaXMgY29tcHV0ZWQgYnkgdGhlIGZvcm11bGE6IG51bWJlciBvZiB3aW5zIC0gbnVtYmVyIG9mIGxvc2VzICsgMCAqIG51bWJlciBvZiBkcmF3cy4gCi0gYEdhbWVgOiBudW1iZXIgb2YgcGFpcndpc2UgY29tcGV0aXRpb24gdGhlIGlzb2xhdGUgaGFzIHBsYXllZC4gVGhlIG51bWJlciBvZiBnYW1lcyBhbiBpc29sYXRlIHBsYXRlZCB3aXRoaW4gYSBjb21tdW5pdHkgc2hvdWxkIGJlIGNvbW11bml0eSBzaXplIG1pbnVzIG9uZS4gCi0gYFJhbmtgOiB0aGUgcmFua3MgYmFzZWQgb24gYFNjb3JlYC4gVGhlIHJhbmtzIHJhbmdlIGZyb20gMSB0byB0aGUgZm9jYWwgY29tbXVuaXR5IHNpemUuIElzb2xhdGVzIHdpdGggdGhlIHNhbWUgc2NvcmVzIGluIGEgY29tbXVuaXR5IGFyZSBnaXZlbiB0aGUgc2FtZSByYW5rLgotIGBQbG90UmFua2A6IGNvbnRpbnVvdXMgcmFuayBmb3IgcGxvdHRpbmcgY29udmVuaWVuY2UuCgoKIyAwMkUgY29tcGV0aXRpb24gcGh5bG9nZW55CgotIENvcnJlbGF0ZSBjb21wZXRpdGlvbiByZXN1bHQgd2l0aCBwaHlsb2dlbmV0aWMgZGlzdGFuY2UKCi0gTWVhc3VyZSB0aGUgcGFpcndpc2UgcGh5bG9nZW5ldGljIGRpc3RhbmNlcyBieSBkaWZmZXJlbmNlIGluIDE2UyBiYXNlIHBhaXJzIGBwYWlyc190YXhvbm9teWAKICAgIC0gQ29hcnNlLWdyYWluZWQgdGF4b25vbXkgKEZhbWlseSBhbmQgR2VudXMpCiAgICAtIENvbXB1dGUgdGhlIHBhaXJ3aXNlIHNlcXVlbmNlIGRpZmZlcmVuY2VzIHVzaW5nIGBCaW9zdHJpbmc6OnBhaXJ3aXNlQWxpZ25tZW50KClgIAogICAgLSBDb21wdXRlIHBhaXJ3aXNlIHRyZWUgZGlzdGFuY2UgdXNpbmcgYGFwZTo6Y29waGVuZXRpYy5waHlsbygpYCBvbiBidWlsdCB0cmVlLiBUcnkgb3V0IGRpZmZlcmVudCB0cmVlIGJ1aWxkaW5nIG1ldGhvZHMKCgojIyBJc29sYXRlcycgUkRQIHRheG9ub215CgpgYGB7ciB3YXJuaW5nID0gRn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkUtY29tcGV0aXRpb25fcGh5bG9nZW55LTAxLXBhaXJzX3RheG9ub215LlIiKQpgYGAKCmBgYHtyfQpwYWlyc190YXhvbm9teSA8LSByZWFkX2NzdihoZXJlOjpoZXJlKCJkYXRhL3RlbXAvcGFpcnNfdGF4b25vbXkuY3N2IikpCnBhaXJzX3RheG9ub215CmBgYAoKCgojIyBJc29sYXRlcycgMTZTIHNlcXVlbmNlIGRpZmZlcmVuY2UKCgpgYGB7ciBldmFsID0gRn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkUtY29tcGV0aXRpb25fcGh5bG9nZW55LTAyLXBhaXJzXzE2Uy5SIikKYGBgCgpgYGB7cn0KcGFpcnNfMTZTIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvdGVtcC9wYWlyc18xNlMuY3N2IikpCnBhaXJzXzE2UwpgYGAKCgpgYGB7ciBpbmNsdWRlID0gRn0KIyBQbG90IHRoZSBpc29sYXRlIDE2UyBhbGlnbm1lbnRzCmlmIChGQUxTRSkgewptc2E6Om1zYVByZXR0eVByaW50KGFsbiwgZmlsZSA9ICJpc29sYXRlc19hbGlnbm1lbnQucGRmIiwgb3V0cHV0PSJwZGYiLCAKICBwYXBlckhlaWdodCA9IDE1LCBwYXBlcldpZHRoID0gMTAsCiAgc2hvd05hbWVzPSJsZWZ0IiwgYXNrRm9yT3ZlcndyaXRlPUZBTFNFLCB2ZXJib3NlPUZBTFNFKQp9CmBgYAoKCiMjIElzb2xhdGVzJyBicmFuY2ggZGlzdGFuY2VzIG9uIHBoeWxvZ2VuZXRpYyB0cmVlIChkZXByZWNhdGVkKQoKYGBge3Igd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyRS1jb21wZXRpdGlvbl9waHlsb2dlbnktMDMtcGFpcnNfdHJlZV9icmFuY2guUiIpCmBgYAoKYGBge3J9CnBhaXJzX3RyZWVfZGlzdGFuY2UgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL3BhaXJzX3RyZWVfZGlzdGFuY2UuY3N2IikpCnBhaXJzX3RyZWVfZGlzdGFuY2UKYGBgCgoKIyBTdW1tYXJ5CgojIyBSZWFkIGFuZCBjb21iaW5lIHBhaXJzIGRhdGEgCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMi1wYWlycy0wMS1yZWFkX2RhdGEuUiIpCmBgYAoKMTg2IHBhaXJzCgpgYGB7cn0KcGFpcnMgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvcGFpcnMuY3N2IikpCnBhaXJzCmBgYAoKClBhaXJzIGRhdGEuZnJhbWUgbWVsdGVkIGJ5IFQwL1Q4IGFuZCB0aHJlZSBpbml0aWFsIGZyZXF1ZW5jaWVzLiAxODZ4M3gyPTExMTYKCmBgYHtyfQpwYWlyc19tZWx0ZWQgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvcGFpcnNfbWVsdGVkLmNzdiIpKQpwYWlyc19tZWx0ZWQKYGBgCgojIyBQbG90IG91dGNvbWVzIHR5cGVzCgpgYGB7ciB3YXJuaW5nID0gRn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMi1wYWlycy0wMi1vdXRjb21lX3R5cGVzLlIiKQpgYGAKCmBgYHtyfQojIHBhaXJzX2xpc3QgPC0gcGFpcnNfZXhhbXBsZV9vdXRjb21lcwojIHBhaXJzX2ZyZXFfZGYgPC0gcGFpcnNfZnJlcQojIFIgZnVuY3Rpb24gZm9yIHBsb3R0aW5nIGZyZXF1ZW5jeSBjaGFuZ2VzCnBsb3RfcGFpcnNfZnJlcSA8LSBmdW5jdGlvbihwYWlyc19saXN0LCBwYWlyc19mcmVxX2RmLCBzaG93X3N0cmlwID0gVFJVRSkgewogICMgQSBsaXN0IG9mIHBhaXJzIHdpdGggQ29tbXVuaXR5LCBJc29sYXRlMSwgYW5kIElzb2xhdGUyCiAgcGFpcnNfbGlzdCAlPiUKICAgICMgSm9pbnQgdGhlIGRmIGBwYWlyc19mcmVxYCB0aGF0IHNhdmVzIGZyZXF1ZW5jeSBkYXRhCiAgICBsZWZ0X2pvaW4ocGFpcnNfZnJlcV9kZiwgYnkgPSBjKCJDb21tdW5pdHkiLCAiSXNvbGF0ZTEiLCAiSXNvbGF0ZTIiKSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUoSXNvbGF0ZTFJbml0aWFsT0RGcmVxID0gZmFjdG9yKElzb2xhdGUxSW5pdGlhbE9ERnJlcSksCiAgICAgIEludGVyYWN0aW9uVHlwZSA9IG9yZGVyZWQoSW50ZXJhY3Rpb25UeXBlLCBjKCJleGNsdXNpb24iLCAiYmlzdGFiaWxpdHkiLCAiY29leGlzdGVuY2UiLCAibmV1dHJhbGl0eSIpKSwKICAgICAgSW50ZXJhY3Rpb25UeXBlRmluZXIgPSBvcmRlcmVkKEludGVyYWN0aW9uVHlwZUZpbmVyLCBjKCJjb21wZXRpdGl2ZSBleGNsdXNpb24iLCAibXV0dWFsIGV4Y2x1c2lvbiIsCiAgICAgICAgInN0YWJsZSBjb2V4aXN0ZW5jZSIsICJmcmVxdWVuY3ktZGVwZW5kZW50IGNvZXhpc3RlbmNlIiwgIm5ldXRyYWxpdHkiKSkpICU+JQogICAgZ2dwbG90KGFlcyh4ID0gVGltZSwgeSA9IElzb2xhdGUxTWVhc3VyZWRGcmVxLCBjb2xvciA9IElzb2xhdGUxSW5pdGlhbE9ERnJlcSwgZ3JvdXAgPSBJc29sYXRlMUluaXRpYWxPREZyZXEpKSArCiAgICBnZW9tX3BvaW50KHNpemUgPSAyKSArCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxLDAuNSkpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoCiAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoNSwgIm1tIiksCiAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkKICAgICAgKSArCiAgICAgIHtpZiAoc2hvd19zdHJpcCA9PSBGQUxTRSkgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgc3RyaXAudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSl9ICsKICAgIGd1aWRlcyhjb2xvciA9IEYpICsKICAgIGxhYnMoeCA9ICJ0cmFuc2ZlciIsIHkgPSAiaXNvbGF0ZSByZWxhdGl2ZSBhYnVuZGFuY2UiKQp9CmBgYAoKCmBgYHtyfQojIFIgZnVuY3Rpb24gZm9yIHBsb3R0aW5nIGJhcnMKcGxvdF9iYXIgPC0gZnVuY3Rpb24ocGFpcnMsIGJhcl9ieSA9ICJJbnRlcmFjdGlvblR5cGUiLCBmaWxsX2J5ID0gIkludGVyYWN0aW9uVHlwZSIsIHNob3dfZmlsbF9sZWdlbmQgPSBGKSB7CiAgIyBNb2RpZnkgYmFycwogIHBhaXJzJEludGVyYWN0aW9uVHlwZUZpbmVyW3BhaXJzJEludGVyYWN0aW9uVHlwZUZpbmVyID09ICJmcmVxdWVuY3ktZGVwZW5kZW50IGNvZXhpc3RlbmNlIl0gPC0gImZyZXF1ZW5jeS1kZXBlbmRlbnRcbmNvZXhpc3RlbmNlIgoKICAjIENvbG9yIHBhbGV0dGVzCiAgaW50ZXJhY3Rpb25fdHlwZSA8LSBjKCJleGNsdXNpb24iLCAiY29leGlzdGVuY2UiLCAibmV1dHJhbGl0eSIsICJtdXR1YWwgZXhjbHVzaW9uIiwgImZyZXF1ZW5jeS1kZXBlbmRlbnRcbmNvZXhpc3RlbmNlIikKICBteUNvbG9yID0gYygiI0RCNzQ2OSIsICIjNTU3QkFBIiwgIiM4NjUwQzQiLCAicmVkIiwgImJsdWUiKQogIG5hbWVzKG15Q29sb3IpIDwtIGludGVyYWN0aW9uX3R5cGUKCiAgIyBQbG90CiAgcGFpcnMgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUoCiAgICAgIEludGVyYWN0aW9uVHlwZSA9IG9yZGVyZWQoSW50ZXJhY3Rpb25UeXBlLCBjKCJleGNsdXNpb24iLCAiY29leGlzdGVuY2UiLCAibmV1dHJhbGl0eSIpKSwKICAgICAgSW50ZXJhY3Rpb25UeXBlRmluZXIgPSBvcmRlcmVkKEludGVyYWN0aW9uVHlwZUZpbmVyLCBjKCJjb21wZXRpdGl2ZSBleGNsdXNpb24iLCAibXV0dWFsIGV4Y2x1c2lvbiIsCiAgICAgICAgInN0YWJsZSBjb2V4aXN0ZW5jZSIsICJmcmVxdWVuY3ktZGVwZW5kZW50XG5jb2V4aXN0ZW5jZSIsICJuZXV0cmFsaXR5IikpKSAlPiUKICAgIGdyb3VwX2J5X2F0KC52YXJzID0gYyhiYXJfYnksIGZpbGxfYnkpKSAlPiUKICAgIHN1bW1hcml6ZShDb3VudCA9IG4oKSwgRnJhY3Rpb24gPSBuKCkvbnJvdyguKSkgJT4lCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX2JhcihhZXNfc3RyaW5nKHggPSBiYXJfYnksIHkgPSAiRnJhY3Rpb24iLCBmaWxsID0gZmlsbF9ieSksIHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9IDEsIHBvc2l0aW9uID0gImRvZGdlIikgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMSkpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG15Q29sb3IpICsKICAgIGZhY2V0X2dyaWQoYXMuZm9ybXVsYShwYXN0ZTAoIn4iLCBiYXJfYnkpKSwgc2NhbGUgPSAiZnJlZV94IikgKwogICAgeyBpZiAoc2hvd19maWxsX2xlZ2VuZCA9PSBGQUxTRSkgZ3VpZGVzKGZpbGwgPSAibm9uZSIpIH0gKwogICAgdGhlbWVfY293cGxvdCgpICsKICAgIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMCwgIm1tIiksCiAgICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSkKfQoKYGBgCgoKRm91ciBleGFtcGxlIG91dGNvbWVzOiBiaXN0YWJpbGl0eSwgY29leGlzdGVuY2UsIGV4Y2x1c2lvbiwgYW5kIG5ldXRyYWxpdHkgCgpgYGB7cn0KcGFpcnNfZXhhbXBsZV9vdXRjb21lcyA8LSByZWFkX2NzdihoZXJlOjpoZXJlKCJkYXRhL291dHB1dC9wYWlyc19leGFtcGxlX291dGNvbWVzLmNzdiIpKQoKIyBQbG90IHBhaXJzIGV4YW1wbGUgZHluYW1pY3MKcF9wYWlyc19leGFtcGxlX291dGNvbWVzIDwtIHBhaXJzX2V4YW1wbGVfb3V0Y29tZXMgJT4lCiAgcGxvdF9wYWlyc19mcmVxKHBhaXJzX2ZyZXFfZGYgPSBwYWlyc19mcmVxLCBzaG93X3N0cmlwID0gRikgKwogIGZhY2V0X2dyaWQoLn5JbnRlcmFjdGlvblR5cGUpCgojIFRoZSBmcmVxdWVuY2llcyBvZiB0aHJlZSBvdXRjb21lcwpwX3BhaXJzX2ludGVyYWN0aW9uIDwtIHBsb3RfYmFyKHBhaXJzLCBiYXJfYnkgPSAiSW50ZXJhY3Rpb25UeXBlIikgKwogIGdlb21fdGV4dChkYXRhID0gZGF0YS5mcmFtZShJbnRlcmFjdGlvblR5cGUgPSAibmV1dHJhbGl0eSIsIHggPSAxLCB5ID0gMSwgbGFiZWwgPSAibiA9IDE4NiBwYWlycyIpLCBtYXBwaW5nID0gYWVzKHggPSB4LCB5ID0geSwgbGFiZWwgPSBsYWJlbCkpCmBgYAoKYGBge3IgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDN9CnAgPC0gcGxvdF9ncmlkKHBfcGFpcnNfaW50ZXJhY3Rpb24sIHBfcGFpcnNfZXhhbXBsZV9vdXRjb21lcywgbmNvbCA9IDEsIGFsaWduID0gInYiLCByZWxfaGVpZ2h0cyA9IGMoMSwgMC41KSkKcApnZ3NhdmUoaGVyZTo6aGVyZSgib3V0cHV0L3JlcG9ydC9maWd1cmUvMDItcGFpcnMtcGFpcnNfb3V0Y29tZXMucGRmIiksIHAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKYGBgCgoKRm91ciBleGFtcGxlIG91dGNvbWVzOiBiaXN0YWJpbGl0eSwgY29leGlzdGVuY2UsIGV4Y2x1c2lvbiwgYW5kIG5ldXRyYWxpdHkgCgpgYGB7ciB3YXJuaW5nID0gRn0KcGFpcnNfZXhhbXBsZV9vdXRjb21lc19maW5lciA8LSByZWFkX2NzdihoZXJlOjpoZXJlKCJkYXRhL291dHB1dC9wYWlyc19leGFtcGxlX291dGNvbWVzX2ZpbmVyLmNzdiIpKQojIFBsb3QgcGFpcnMgZXhhbXBsZSBkeW5hbWljcwpwX3BhaXJzX2V4YW1wbGVfb3V0Y29tZXNfZmluZXIgPC0gcGFpcnNfZXhhbXBsZV9vdXRjb21lc19maW5lciAlPiUKICBwbG90X3BhaXJzX2ZyZXEocGFpcnNfZnJlcV9kZiA9IHBhaXJzX2ZyZXEsIHNob3dfc3RyaXAgPSBGKSArCiAgZmFjZXRfZ3JpZCgufkludGVyYWN0aW9uVHlwZUZpbmVyKQoKIyBUaGUgZnJlcXVlbmNpZXMgb2YgZml2ZSBmaW5lciBvdXRjb21lcwpwX3BhaXJzX2ludGVyYWN0aW9uX2ZpbmVyIDwtIHBsb3RfYmFyKHBhaXJzLCBiYXJfYnkgPSAiSW50ZXJhY3Rpb25UeXBlRmluZXIiLCBmaWxsX2J5ID0gIkludGVyYWN0aW9uVHlwZSIsIHNob3dfZmlsbF9sZWdlbmQgPSBUKQoKYGBgCgpgYGB7ciBmaWcud2lkdGggPSA1LCBmaWcuaGVpZ2h0ID0gM30KIyBDb21iaW5lIHBsb3QKI3RoZW1lX3NldCh0aGVtZV9jb3dwbG90KGZvbnRfc2l6ZT0xMikpCnAgPC0gcGxvdF9ncmlkKHBfcGFpcnNfaW50ZXJhY3Rpb25fZmluZXIsIHBfcGFpcnNfZXhhbXBsZV9vdXRjb21lc19maW5lciwgbmNvbCA9IDEsIGFsaWduID0gInYiLCByZWxfaGVpZ2h0cyA9IGMoMSwgMC40KSkKcApnZ3NhdmUoaGVyZTo6aGVyZSgib3V0cHV0L3JlcG9ydC9maWd1cmUvMDItcGFpcnMtcGFpcnNfb3V0Y29tZXMucGRmIiksIHAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKYGBgCgoKIyMgUGFpcnMgdGF4b25vbXkgdnMuIG91dGNvbWUgb2YgcGFpcndpc2UgY29tcGV0aXRpb24KCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyLXBhaXJzLTAzLXRheG9ub215LlIiKQpgYGAKCgojIyMgUkRQIHRheG9ub215CgpGZXJtZW50ZXIgdnMuIEludGVyYWN0aW9uIHR5cGUKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmxvYWQoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL3BhaXJzX2Jhcl9wbG90cy5SZGF0YSIpKQpwX3BhaXJzX2ludGVyYWN0aW9uX2Zlcm1lbnRlcgpnZ3NhdmUoaGVyZTo6aGVyZSgib3V0cHV0L3JlcG9ydC9maWd1cmUvMDItcGFpcnMtZmVybWVudGVyX2ludGVyYWN0aW9uLnBkZiIpLCBwX3BhaXJzX2ludGVyYWN0aW9uX2Zlcm1lbnRlciwgd2lkdGggPSA1LCBoZWlnaHQgPSA1KQoKYGBgCgpGYW1pbHkgdnMuIEludGVyYWN0aW9uIHR5cGUKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CnBfcGFpcnNfaW50ZXJhY3Rpb25fZmFtaWx5Cmdnc2F2ZShoZXJlOjpoZXJlKCJvdXRwdXQvcmVwb3J0L2ZpZ3VyZS8wMi1wYWlycy1mYW1pbHlfaW50ZXJhY3Rpb24ucGRmIiksIHBfcGFpcnNfaW50ZXJhY3Rpb25fZmFtaWx5LCB3aWR0aCA9IDUsIGhlaWdodCA9IDUpCmBgYAoKIyMjIFBhaXJ3aXNlIDE2UyBkaWZmZXJlbmNlcwoKUGFpcndpc2UgMTZTIGRpZmZlcmVuY2VzCgpgYGB7cn0KcGFpcnMgJT4lCiAgZmlsdGVyKCFpcy5uYShTZXFEaWZmZXJlbmNlKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IFNlcURpZmZlcmVuY2UsIGZpbGwgPSBQYWlyRmVybWVudGVyKSkgKwogIGdlb21faGlzdG9ncmFtKGNvbCA9ICJibGFjayIsIGJpbndpZHRoID0gMikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgbGFicyh4ID0gInBhaXJ3aXNlIDE2UyBiYXNlIHBhaXIgZGlmZmVyZW5jZXMiKSArCiAgZ2d0aXRsZSgiIikKYGBgCgpDb2Fyc2VkLWdyYWluZWQgMTZTIHNlcXVlbmNlIGRpZmZlcmVuY2UKCmBgYHtyfQpwYWlycyAlPiUKICBmaWx0ZXIoIWlzLm5hKFNlcURpZmZlcmVuY2UpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gU2VxRGlmZmVyZW5jZSwgZmlsbCA9IFBhaXJGZXJtZW50ZXIpKSArCiAgZ2VvbV9oaXN0b2dyYW0oY29sID0gImJsYWNrIiwgYmlud2lkdGggPSAxMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgbGFicyh4ID0gInBhaXJ3aXNlIDE2UyBiYXNlIHBhaXIgZGlmZmVyZW5jZXMiKSArCiAgZ2d0aXRsZSgiIikKCmBgYAoKCmBgYHtyIGluY2x1ZGUgPSBGfQojIDE2UyBzZXF1ZW5jZSBkaWZmZXJlbmNlIHZzLiBJbnRlcmFjdGlvbiB0eXBlCnBhaXJzX2ludGVyYWN0aW9uXzE2U19jdXQgJT4lCiAgZ2dwbG90KGFlcyh4ID0gU2VxRGlmZmVyZW5jZSwgeSA9IEZyYWNDb2V4dCkpICsKICBnZW9tX2NvbChjb2wgPSAiYmxhY2siLCBmaWxsID0gIndoaXRlIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpgYGAKCgpgYGB7ciBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQpwX3BhaXJzX2ludGVyYWN0aW9uXzE2U19jdXQKYGBgCgoKCiMgUmVsYXRpdmUgYWJ1bmRhbmNlIHdpdGhpbiBwYWlycyAKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyLXBhaXJzLTA0LXBhaXJzX3JlbGF0aXZlX2FidW5kYW5jZS5SIikKYGBgCgoKUmVsYXRpdmUgYWJ1bmRhbmNlIG9mIGZlcm1lbnRlciB2cy4gbm9uLWZlcm1lbnRlciBwYWlycwoKYGBge3J9CmxvYWQoaGVyZTo6aGVyZSgiZGF0YS90ZW1wL3BhaXJzX2hpc3RfcGxvdHMuUmRhdGEiKSkKcGFpcnNfZnJlcV90YXhvbm9teV9mZXJtZW50ZXIgJT4lCiAgZmlsdGVyKFRpbWUgPT0gIlQ4IikgJT4lCiAgZmlsdGVyKCFJc29sYXRlMU1lYXN1cmVkRnJlcSAlaW4lIGMoMCwxKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gSXNvbGF0ZTFNZWFzdXJlZEZyZXEpLCBjb2wgPSAiYmxhY2siLCBmaWxsID0gIndoaXRlIikgKwogIGZhY2V0X2dyaWQoUGFpckZlcm1lbnRlcn4uLCBzY2FsZSA9ICJmcmVlIikgKwogIHRoZW1lX2J3KCkgKwogIGxhYnMoImZyZXF1ZW5jaWVzIG9mIGlzb2xhdGUgMSBhdCBUOCIpCmBgYAoKUmVsYXRpdmUgYWJ1bmRhbmNlIG9mIEVudGVyb2JhY3RlcmlhY2VhZSBhbmQgUHNldWRvbW9uYWRhY2VhZSBwYWlycwoKYGBge3J9CnBhaXJzX2ZyZXFfdGF4b25vbXlfZmFtaWx5ICU+JQogIGZpbHRlcihUaW1lID09ICJUOCIpICU+JQogIGZpbHRlcighSXNvbGF0ZTFNZWFzdXJlZEZyZXEgJWluJSBjKDAsMSkpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IElzb2xhdGUxTWVhc3VyZWRGcmVxKSwgY29sID0gImJsYWNrIiwgZmlsbCA9ICJ3aGl0ZSIpICsKICBmYWNldF9ncmlkKFBhaXJGYW1pbHl+Liwgc2NhbGUgPSAiZnJlZSIpICsKICB0aGVtZV9idygpICsKICBsYWJzKCJmcmVxdWVuY2llcyBvZiBpc29sYXRlIDEgYXQgVDgiKQoKYGBgCgoKCiMgRnJhY3Rpb24gb2YgcGFpcndpc2UgY29leGlzdGVuY2Ugd2l0aGluIGNvbW11bml0eSAgCgpgYGB7cn0KY29tbXVuaXRpZXNfcGFpcl9jb2V4dCA8LSBwYWlycyAlPiUKICBtdXRhdGUoQ29tbXVuaXR5ID0gb3JkZXJlZChDb21tdW5pdHksIGxldmVscyA9IGNvbW11bml0aWVzJENvbW11bml0eSkpICU+JQogIGZpbHRlcihJbnRlcmFjdGlvblR5cGUgIT0gIiIpICU+JQogIGZpbHRlcihJbnRlcmFjdGlvblR5cGUgJWluJSBjKCJleGNsdXNpb24iLCAiY29leGlzdGVuY2UiKSkgJT4lCiAgZ3JvdXBfYnkoQ29tbXVuaXR5LCBJbnRlcmFjdGlvblR5cGUpICU+JQogIHN1bW1hcml6ZShDb3VudCA9IG4oKSkgJT4lCiAgc3ByZWFkKEludGVyYWN0aW9uVHlwZSwgQ291bnQpICU+JQogIG11dGF0ZShGcmFjQ29leHQgPSBjb2V4aXN0ZW5jZSAvIChjb2V4aXN0ZW5jZSArIGV4Y2x1c2lvbikpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoQ29tbXVuaXR5U2l6ZSA9IGNvbW11bml0aWVzJENvbW11bml0eVNpemUpCgpjb21tdW5pdGllc19wYWlyX2NvZXh0JEZyYWNDb2V4dFtpcy5uYShjb21tdW5pdGllc19wYWlyX2NvZXh0JEZyYWNDb2V4dCldIDwtIDAKYGBgCgpGcmFjdGlvbiBvZiBjb2V4aXN0ZW5jZSBpbiAxMyBjb21tdW5pdGllcwoKYGBge3J9CnBfY29tbXVuaXRpZXNfcGFpcl9jb2V4dCA8LSAKY29tbXVuaXRpZXNfcGFpcl9jb2V4dCAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9iYXIoYWVzKHggPSBDb21tdW5pdHksIHkgPSBGcmFjQ29leHQpLCBzdGF0ID0gImlkZW50aXR5IiwgY29sID0gMSkgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsKICBsYWJzKHggPSAiY29tbXVuaXR5IiwgeSA9ICJmcmFjdGlvbiBvZiBjb2V4aXN0ZW5jZSIpCgpwX2NvbW11bml0aWVzX3BhaXJfY29leHQKZ2dzYXZlKCJmaWd1cmUvMDItY29tbXVuaXRpZXNfZnJhY3Rpb25fY29leGlzdGVuY2UucG5nIiwgcF9jb21tdW5pdGllc19wYWlyX2NvZXh0LCB3aWR0aCA9IDUsIGhlaWdodCA9IDMpCmBgYAoKIyBDb21tdW5pdHkgaGllcmFyY2h5IGluIGNvbW11bml0aWVzCgoKRnJvbSBIaWdnaW5zMjAxNywgdGhlIGNvbXBldGl0aXZlIHNjb3JlICRzX2kkIG9mIGVhY2ggc3RyYWluICRpJCB3YXMgZGVmaW5lZCBhcyBpdHMgbWVhbiBmcmFjdGlvbiAkZl97aWp9JCBhZnRlciBjby1jdWx0dXJlIHdpdGggZWFjaCBvZiB0aGUgJG4tMSQgY29tcGV0aXRvciBzdHJhaW5zOgoKJCRzX2k9KFxzdW1fe2lcbmVxIGp9Zl97aWp9KS8obi0xKSQkCgpUaGUgaGllcmFyY2h5IHNjb3JlICRoJCBmb3IgYW4gbi1tZW1iZXIgbmV0b3drciBpcyBjYWxjdWxhdGVkIGFzOgoKJCRoID0gXHN1bV97c19pPnNfan1mX3tpan0kJAoKYGBge3J9CmNvbW11bml0aWVzX2hpZXJhcmNoeSA8LSByZWFkX2NzdihoZXJlOjpoZXJlKCJkYXRhL3RlbXAvY29tbXVuaXRpZXNfaGllcmFyY2h5LmNzdiIpKQoKcF9jb21tdW5pdGllc19oaWVyYXJjaHkgPC0gY29tbXVuaXRpZXNfaGllcmFyY2h5ICU+JQogIGdncGxvdCgpICsKICBnZW9tX2JhcihhZXMoeCA9IENvbW11bml0eSwgeSA9IEhpZXJhcmNoeVNjb3JlKSwgc3RhdCA9ICJpZGVudGl0eSIsIGNvbCA9IDEpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAxKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKSArCiAgbGFicyh4ID0gImNvbW11bml0eSIsIHkgPSAiaGllcmFyY2h5IHNjb3JlIikKCnBfY29tbXVuaXRpZXNfaGllcmFyY2h5CnBkZihoZXJlOjpoZXJlKCJvdXRwdXQvZmlndXJlL2NvbW11bml0aWVzX2hpZXJhcmNoeS5wZGYiKSwgd2lkdGggPSA1LCBoZWlnaHQgPSAzKTsgcF9jb21tdW5pdGllc19oaWVyYXJjaHk7IGludmlzaWJsZShkZXYub2ZmKCkpCgogICAgCmBgYAoKCgoKIyBHcm93dGggdHJhaXRzIHZzIGNvZXhpc3RlbmNlIChEZXByZWNhdGVkKQoKYGBge3J9CmlmIChGQUxTRSkgewpzb3VyY2UoInNjcmlwdC8wMi1wYWlycy0wNS1ncm93dGhfcmF0ZXMuUiIpCnBhaXJzX2dyb3d0aF9yYXRlCnBfcGFpcnNfZ3Jvd3RoX3JhdGVfaGlzdApwX3BhaXJzX2dyb3d0aF9yYXRlX2RlbnNpdHkKCnBkZihoZXJlOjpoZXJlKCJvdXRwdXQvZmlndXJlL3BhaXJzX2dyb3d0aF9yYXRlc19oaXN0LnBkZiIpLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA1KTsgZm9yIChpIGluIDE6MTEpIHByaW50KHBfcGFpcnNfZ3Jvd3RoX3JhdGVfaGlzdF9saXN0W1tpXV0pOyBpbnZpc2libGUoZGV2Lm9mZigpKQoKcGRmKGhlcmU6OmhlcmUoIm91dHB1dC9maWd1cmUvcGFpcnNfZ3Jvd3RoX3JhdGVzX2RlbnNpdHkucGRmIiksIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpOyBmb3IgKGkgaW4gMToxMSkgcHJpbnQocF9wYWlyc19ncm93dGhfcmF0ZV9kZW5zaXR5X2xpc3RbW2ldXSk7IGludmlzaWJsZShkZXYub2ZmKCkpCn0KYGBgCgoKCgoKCgo=